Переменное назначение и модификация (в python)
Когда я запускал этот script (Python v2.6):
a = [1,2]
b = a
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2,3]
Я ожидал print b
для вывода [1,2]
. Почему b изменился, когда все, что я сделал, изменилось? Является ли b постоянно привязанным к? Если да, могу ли я сделать их независимыми? Как?
Ответы
Ответ 1
Управление памятью в Python включает в себя локальную ячейку памяти кучи, содержащую все объекты и структуры данных Python.
Время выполнения Python работает только с ссылками на объекты (все они живут в куче): то, что происходит на стеке Python, всегда ссылается на ценности, которые живут где-то в другом месте.
>>> a = [1, 2]
![python variables]()
>>> b = a
![python variables]()
>>> a.append(3)
![python variables]()
Здесь мы можем ясно видеть, что переменная b
связана с тем же объектом, что и a
.
Вы можете использовать оператор is
для проверки, если два объекта физически одинаковы, это означает, что они имеют одинаковый адрес в памяти. Это также можно проверить также с помощью функции id()
.
>>> a is b
>>> True
>>> id(a) == id(b)
>>> True
Итак, в этом случае вы должны явно запросить копию.
Как только вы это сделаете, больше не будет связи между двумя отдельными объектами списка.
>>> b = list(a)
>>> a is b
>>> False
![python variables]()
Ответ 2
Объекты в Python хранятся по ссылке: вы не назначаете значение a
на b
, а указатель на объект, на который указывает a
.
Чтобы эмулировать присвоение по значению, вы можете сделать копию следующим образом:
import copy
b = copy.copy(a)
# now the code works as "expected"
Помните, что это имеет недостатки производительности.
В случае массива существует специальный метод, который использует срезы:
b = a[:]
# code also works as expected here
Обновление. В дополнение к этому, с некоторыми объектами вы можете использовать конструктор - это включает в себя списки:
b = list(a)
Ответ 3
Короткий ответ - указатели.
При вводе b = a
устанавливается b
на тот же массив, на который смотрит a
. Вы должны создать новый массив с копиями элементов для их разделения. В этом случае что-то вроде b = [n for n in a]
будет работать нормально. Для более сложных операций вы можете проверить http://docs.python.org/library/copy.html.
Ответ 4
Возможно, вы захотите посмотреть эту ссылку. Проблема, с которой вы здесь столкнулись, - это a
и b
, указывающие на одну и ту же ячейку памяти, поэтому ее изменение меняет другую. Вместо этого вы хотите сделать что-то вроде этого:
a = [1,2]
b = list(a)
Ответ 5
a
является указателем на список [1,2]
.
Когда вы выполняете назначение b = a
, значение b является адресом списка [1,2]
.
Итак, когда вы делаете a.append(3)
, вы фактически не меняете a
, вы меняете список, на который указывает a
. Поскольку a
и b
оба указывают на один и тот же список, оба они изменяются при изменении другого.
Ответ 6
Если вы просто хотите скопировать содержимое списка a в b, вместо того чтобы сделать b указателем на:
b = a[:]
Использование оператора slice скопирует содержимое списка в b, чтобы вы, например, стали:
a = [1,2]
b = a[:]
a.append(3)
print a
>>>> [1,2,3]
print b
>>>> [1,2]