2010-06-17 5 views
27

У меня странная проблема в Python 2.6.5 с помощью Numpy. Я назначаю массив numpy, а затем приравниваю к нему новую переменную. Когда я выполняю любую операцию с новым массивом, значения оригинала также меняются. Почему это? См. Пример ниже. Пожалуйста, просветите меня, поскольку я довольно новичок в Python и вообще программирую.проблема с присвоением массива numpy

-Sujan

>>> import numpy as np 
>>> a = np.array([[1,2],[3,4]]) 
>>> b = a 
>>> b 
array([[1, 2], 
     [3, 4]]) 
>>> c = a 
>>> c 
array([[1, 2], 
     [3, 4]]) 
>>> c[:,1] = c[:,1] + 5 
>>> c 

array([[1, 7], 
     [3, 9]]) 
>>> b 
array([[1, 7], 
     [3, 9]]) 
>>> a 
array([[1, 7], 
     [3, 9]]) 

ответ

56

Это на самом деле не проблема вообще; это способ, которым массивы (и другие объекты) работают на Python.

Подумайте об этом так: массив, который вы создали в вашем примере кода, является объектом, который находится в каком-либо месте в памяти. Но вы не можете использовать его в своей программе, говоря Python, где в памяти идти искать его; вы должны дать ему имя. Когда вы пишете

a = np.array([[1,2],[3,4]]) 

вы оба создания массива и создать имя, a, что относится к нему. С этого момента Python знает, что a ссылается на «адрес памяти 0x123674283» (или что-то еще). Там есть внутренняя таблица в среде выполнения Python (так называемая «таблицей символов», если я правильно помню), которая содержит всю эту информацию, так что после того, как выше строка кода Python работает, эта таблица будет содержать

..., 
'a' : 0x123674283, 
... 

При назначении значение одной переменной в другую, как

b = a 

Python не копирует весь массив, потому что если бы это был большой массив, это заняло бы много времени. Вместо этого он переходит в таблицу символов и копирует адрес памяти для a в новую строку в таблице для b. Таким образом, вы завершаете с

..., 
'a' : 0x123674283, 
..., 
'b' : 0x123674283, 
... 

Итак, вы видите, a и b фактически ссылаясь на то же место в памяти, то есть тот же объект. Любые изменения, внесенные вами в один, будут отражены в другом, так как они всего лишь два имени для одного и того же.

Если вы хотите сделать копию массива, вы должны вызвать метод, чтобы сделать это явно. У массивов Numpy есть метод copy, который вы можете использовать только для этой цели. Так что, если вы пишете

b = a.copy() 

тогда Python будет первым фактически сделать копию массива - то есть, он выделяет новую область памяти, скажем, по адресу 0x123904381, затем идет в адрес памяти 0x123674283 и копии всех значения массива от последнего раздела памяти до первого. Таким образом, у вас есть одно и то же содержание, сидящее в двух разных местах в памяти.

..., 
'a' : 0x123674283, 
..., 
'b' : 0x123904381, 
... 

Теперь, когда вы измените один из элементов b, что изменения не будут отображаться в a, так как a и b больше не относятся к одной и той же секции памяти компьютера. Поскольку есть две независимые копии данных массива, вы можете изменить один, не затрагивая другой.

+6

Благодарю вас за отличное описание. Излишне говорить, что это устранило проблему, но я действительно ценю, что вы тратите время на объяснение. Ты просветил меня! – Sujan

+1

«Python не копирует весь массив, потому что если бы это был большой массив, это заняло бы много времени». - Я бы сказал, что речь идет не о времени, которое потребуется, и о том, что если вы не реализуете такие вещи таким образом, вам нужно ввести что-то вроде отдельного типа указателя, и это усложняет ситуацию. – user2357112

1

Вкратце, присваивание переменной создает новую ссылку на существующий объект.

A = object # A points to object in memory 
    B = A  # B points to the same object 
Смежные вопросы