2015-04-21 4 views
5

Я новичок в Python, и я не хочу, чтобы эти массивы копировать друг друга, но они автоматически:Python массивы автоматически копируют друг друга

a = numpy.zeros(4) 
b = a 
a[1] = 10 
print b[1] 

и возвращает 10 вместо 0. Как Я отключу эти два массива?

+4

Назначение не создает копию. Чтобы понять, почему ваше ожидание было неправильным, см. [Факты и мифы о именах и ценностях Python] (http://nedbatchelder.com/text/names.html) от Ned Batchelder. Важно прочитать подробное если вы действительно поймете Python. –

ответ

2

Вам нужна копия:

b = a.copy() 

b = a создает ссылку так a is b, они оба указывают на то же место в памяти, a.copy() фактически создает новый объект.

In [5]: a = numpy.zeros(4)  
In [6]: b = a # reference 
In [7]: id(a) 
Out[7]: 140335847505968  
In [8]: id(b)   # same id's 
Out[8]: 140335847505968  
In [9]: a is b 
Out[9]: True  
In [10]: b = a.copy() # new object  
In [11]: id(a) 
Out[11]: 140335847505968  
In [12]: id(b) # # now different id's 
Out[12]: 140335437696176  
In [13]: a is b # b is no longer pointing to the same memory location 
Out[13]: False 

Если вы отрезаете массив, используя basic slicing, то идентификаторы будут отличаться, но любые изменения будут отражены в обоих а и Ь, как при использовании основных Индексация Все массивы, порожденные основной нарезка всегда вид исходного массива. A view is Массив, который не имеет собственных данных, но вместо этого ссылается на данные другого массива. Таким образом, представление представляет собой новый объект, но содержимое по-прежнему принадлежит исходному массиву.

Однако при использовании advanced indexingAdvanced индексирования всегда возвращает копию данных

In [141]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
In [142]: b = a[1:7:2] # basic indexing/view 
In [143]: id(a) 
Out[143]: 140335437385856  
In [144]: id(b)  
Out[144]: 140335437356528  
In [145]: b[0] = 999  
In [146]: a 
Out[146]: array([ 0, 999, 2, 3, 4, 5, 6, 7, 8, 9]) 
In [148]: b 
Out[148]: array([999, 3, 5])  
In [149]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [150]: b = a[[0,3,5]] # advanced indexing/copy 
In [151]: b 
Out[151]: array([0, 3, 5])  
In [152]: b[0] = 999  
In [153]: a 
Out[153]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [154]: b 
Out[154]: array([999, 3, 5]) 
In [157]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
In [158]: b = a[a] # copy 
In [159]: b 
Out[159]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [160]: b[0] = 99  
In [161]: a 
Out[161]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [162]: b 
Out[162]: array([99, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

Это специфическое Numpy поведения, нарезку регулярного питона плоский списка всегда будет создавать новый список, в котором изменения в не будут отражено в b.

In [190]: a = [1,2,3,4,5] 

In [191]: b = a[:3] 

In [192]: b[0] = 999 

In [193]: a 
Out[193]: [1, 2, 3, 4, 5] 

In [194]: b 
Out[194]: [999, 2, 3] 

Где вы будете пойманы со списком питона, если список содержит подсписки и создать неполную копию:

In [197]: a = [[1,2,3],[4,5]] 
In [198]: b = a[:]  
In [199]: id(a) 
Out[199]: 140335437468296  
In [200]: id(b) 
Out[200]: 140335437417992 
In [201]: b[0][0] = 999 
In [202]: b 
Out[202]: [[999, 2, 3], [4, 5]] 
In [203]: a 
Out[203]: [[999, 2, 3], [4, 5]] 

Вы должны были бы сделать copy.deepcopy:

In [204]: a = [[1,2,3],[4,5]]  
In [205]: from copy import deepcopy 
In [206]: b = deepcopy(a)  
In [207]: b[0][0] = 999  
In [208]: b 
Out[208]: [[999, 2, 3], [4, 5]]  
In [209]: a 
Out[209]: [[1, 2, 3], [4, 5]] 
+0

Следует отметить d, что 'a.copy()' недействителен Python 2, который использует OP. – erb

+3

@erb, он также работает в python2, OP имеет массив numpy, а не список. –

+1

Извините, вы правы, пропустили это. – erb

-1

Помните, что списки в Python изменяемы, что означает, что когда вы выполняете операцию присваивания, она не создает его копию, а вместо этого копирует ссылку. Это означает, что обе переменные являются одним и тем же списком.

можно сделать, например:

b = a[::], который создает копию исходного списка.

В любом случае, я бы рекомендовал вам прочитать раздел списков Python.org для получения дополнительной информации.

+3

Назначение работает одинаково независимо от того, присвоено ли значение является неизменным. Я проигнорировал этот ответ, потому что он добавляет излишнюю путаницу к тому, что должно быть более простым объяснением. Кроме того, 'b = a [::]' чаще всего записывается 'b = a [:]'. –

+3

Ломаное копирование не работает с массивами numpy. – Shashank

-1

Вы можете использовать модуль копирования, как этот

from copy import copy 
a = numpy.zeros(4) 
b = copy(a) 
a[1] = 10 
print b[1] 

Это связано с тем, что, когда вы делаете b = a вы назначаете ссылку на a в b.

Более подробно об этом можно найти в этом ответе: How to clone or copy a list?

+3

Это хорошее знание общего назначения о копировании, но в конкретном случае массивов numpy вы можете рассчитывать на массив, имеющий метод 'copy'. –

4

«Массивы автоматически копируют друг друга» ложное заявление по нескольким причинам.Основная причина в том, что у вас есть только один массив и два имени переменных, которые относятся к этому массиву.

Вот три способа скопировать Numpy массива (то есть создать другой массив точно, как это):.

>>> a = numpy.zeros(4) 
>>> b = a.copy() 
>>> c = numpy.copy(a) 
>>> d = numpy.array(a) 
>>> a[1] = 10 
>>> a 
array([ 0., 10., 0., 0.]) 
>>> b 
array([ 0., 0., 0., 0.]) 
>>> c 
array([ 0., 0., 0., 0.]) 
>>> d 
array([ 0., 0., 0., 0.]) 

Обратите внимание, что срез копирования (например e = a[:]) будет не работы с Numpy массивами

+0

"создает другой массив, который является глубокой копией первого", немного вводит в заблуждение: то, что делает операция slice, создает другой массив (т. Е. Новый объект Python типа 'numpy.ndarray'), который * разделяет * то же самое блок данных как исходный массив. Нет никакого копирования массива * данных * происходит, глубоко или иначе. –

+0

@MarkDickinson Это глубокая копия. Попробуйте 'a = numpy.zeros (4); b = a [:]; a [0] - b [0]', и вы увидите, что он дает вам False. Я тоже был удивлен этим поведением. Это определенно отличается от списков. Однако, даже если это глубокая копия в Python, у вас есть два разных объекта, которые указывают на один и тот же адрес в памяти. При назначении значение на этом адресе изменяется, поэтому вы видите изменение между объектами. – Shashank

+2

Это потому, что когда вы вытаскиваете 'a [0]' или 'b [0]', вы эффективно боксируете незанятое значение, хранящееся в массиве, и создаете новый объект Python в этой точке. Попробуйте 'a [0] - [0]', и вы также увидите 'False'. Затем попробуйте изменить 'a': вы увидите, что содержимое' b' также изменяется (и наоборот). –

Смежные вопросы