Я иногда вижу синтаксис списка списка, используемый в коде Python следующим образом:
newList = oldList[:]
Конечно, это то же самое, что:
newList = oldList
Или я что-то не хватает?
Я иногда вижу синтаксис списка списка, используемый в коде Python следующим образом:
newList = oldList[:]
Конечно, это то же самое, что:
newList = oldList
Или я что-то не хватает?
Как и NXC, имена переменных Python фактически указывают на объект, а не на определенное место в памяти.
newList = oldList
создаст две разные переменные, которые указывают на один и тот же объект, поэтому изменение oldList
также изменит newList
.
Однако, когда вы делаете newList = oldList[:]
, он "разрезает" список и создает новый список. Значения по умолчанию для [:]
равны 0 и концу списка, поэтому он копирует все. Поэтому он создает новый список со всеми данными, содержащимися в первом, но оба могут быть изменены без изменения другого.
[:]
Мелкие копии списка, создавая копию структуры списка, содержащей ссылки на исходные элементы списка. Это означает, что операции с копией не влияют на структуру оригинала. Однако, если вы что-то делаете с членами списка, оба списка по-прежнему относятся к ним, поэтому обновления будут отображаться, если к элементам будет доступ через оригинал.
A Deep Copy также сделает копии всех членов списка.
В приведенном ниже фрагменте кода показана мелкая копия в действии.
# ================================================================
# === ShallowCopy.py =============================================
# ================================================================
#
class Foo:
def __init__(self, data):
self._data = data
aa = Foo ('aaa')
bb = Foo ('bbb')
# The initial list has two elements containing 'aaa' and 'bbb'
OldList = [aa,bb]
print OldList[0]._data
# The shallow copy makes a new list pointing to the old elements
NewList = OldList[:]
print NewList[0]._data
# Updating one of the elements through the new list sees the
# change reflected when you access that element through the
# old list.
NewList[0]._data = 'xxx'
print OldList[0]._data
# Updating the new list to point to something new is not reflected
# in the old list.
NewList[0] = Foo ('ccc')
print NewList[0]._data
print OldList[0]._data
Запуск в оболочке python дает следующую расшифровку. Мы можем видеть список делается с копиями старых объектов. Один из объектов может иметь его состояние обновляется по ссылке через старый список, а обновления могут быть когда объект просматривается через старый список. Наконец, изменение ссылка в новом списке, как видно, не отражена в старом списке, поскольку новый список теперь относится к другому объекту.
>>> # ================================================================
... # === ShallowCopy.py =============================================
... # ================================================================
... #
... class Foo:
... def __init__(self, data):
... self._data = data
...
>>> aa = Foo ('aaa')
>>> bb = Foo ('bbb')
>>>
>>> # The initial list has two elements containing 'aaa' and 'bbb'
... OldList = [aa,bb]
>>> print OldList[0]._data
aaa
>>>
>>> # The shallow copy makes a new list pointing to the old elements
... NewList = OldList[:]
>>> print NewList[0]._data
aaa
>>>
>>> # Updating one of the elements through the new list sees the
... # change reflected when you access that element through the
... # old list.
... NewList[0]._data = 'xxx'
>>> print OldList[0]._data
xxx
>>>
>>> # Updating the new list to point to something new is not reflected
... # in the old list.
... NewList[0] = Foo ('ccc')
>>> print NewList[0]._data
ccc
>>> print OldList[0]._data
xxx
Как уже было сказано, я просто добавлю простую демонстрацию:
>>> a = [1, 2, 3, 4]
>>> b = a
>>> c = a[:]
>>> b[2] = 10
>>> c[3] = 20
>>> a
[1, 2, 10, 4]
>>> b
[1, 2, 10, 4]
>>> c
[1, 2, 3, 20]
Никогда не думайте, что "a = b" в Python означает "копировать b в a". Если с обеих сторон есть переменные, вы не можете этого знать. Вместо этого подумайте об этом как "дайте b дополнительное имя a".
Если b - неизменяемый объект (например, число, кортеж или строка), то да, эффект заключается в том, что вы получаете копию. Но это потому, что, когда вы имеете дело с неизменяемыми (что, возможно, должно было быть названо только для чтения, неизменным или WORM), вы всегда получаете копию по определению.
Если b является изменчивым, вы всегда должны сделать что-то дополнительное, чтобы убедиться, что у вас есть подлинная копия. Всегда. Со списками это так же просто, как срез: a = b [:].
Мутация также является причиной того, что это:
def myfunction(mylist=[]):
pass
... не совсем делает то, что вы думаете.
Если вы из C-фона: то, что осталось от "=", является указателем, всегда. Все переменные - указатели, всегда. Если вы поместите переменные в список: a = [b, c], вы указали указатели на значения, на которые указывают b и c в списке, на который указывает a. Если вы затем установите [0] = d, указатель в позиции 0 теперь указывает на то, что d указывает на.
См. также модуль-копия: http://docs.python.org/library/copy.html
Неверная копия: (копирует куски памяти из одного места в другое)
a = ['one','two','three']
b = a[:]
b[1] = 2
print id(a), a #Output: 1077248300 ['one', 'two', 'three']
print id(b), b #Output: 1077248908 ['one', 2, 'three']
Deep Copy: (копирует ссылку на объект)
a = ['one','two','three']
b = a
b[1] = 2
print id(a), a #Output: 1077248300 ['one', 2, 'three']
print id(b), b #Output: 1077248300 ['one', 2, 'three']