Синтаксис фрагмента списка Python используется без очевидной причины
-
11-07-2019 - |
Вопрос
Иногда я вижу синтаксис фрагмента списка, используемый в коде Python, следующим образом:
newList = oldList[:]
Конечно, это то же самое, что:
newList = oldList
Или я что-то упускаю?
Решение
Как сказал NXC, имена переменных Python на самом деле указывают на объект, а не на конкретное место в памяти.
newList = oldList
создаст две разные переменные, указывающие на один и тот же объект, поэтому изменится oldList
тоже бы изменился newList
.
Однако, когда вы делаете newList = oldList[:]
, он «разрезает» список и создает новый список.Значения по умолчанию для [:]
равны 0 и концу списка, поэтому он копирует все.Поэтому он создает новый список со всеми данными, содержащимися в первом, но оба могут быть изменены без изменения другого.
Другие советы
[:]
мелкие копии списка, делая копия структуры списка, содержащая ссылки на оригинальные элементы списка. Это означает, что операции с копией не влияют на структуру оригинала. Однако, если вы что-то делаете с участниками списка, оба списка по-прежнему ссылаются на них, поэтому обновления будут отображаться, если доступ к элементам осуществляется через оригинал. Р>
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 является изменяемым, вам всегда нужно делать что-то дополнительное, чтобы быть уверенным, что у вас есть верная копия . Всегда . Со списками это так же просто, как срез: & nbsp; a = b [:]. Р>
Изменчивость также является причиной того, что это:
def myfunction(mylist=[]):
pass
... не совсем так, как вы думаете.
Если вы из C-фона: то, что осталось от '=', это указатель, всегда. Все переменные являются указателями, всегда. Если вы помещаете переменные в список: & nbsp; a = [b, c], вы помещаете указатели на значения, на которые указывают b и c в списке, на который указывает a. Если затем вы установите a [0] = d, указатель в позиции 0 теперь указывает на то, на что указывает d. Р>
См. также модуль копирования: & nbsp; http://docs.python.org/ библиотека / 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']