Когда фрагмент делает мелкую копию, а когда он делает глубокую копию в Python 3 - PullRequest
0 голосов
/ 28 февраля 2019
bs = [1, 2, 3]
print(id(bs))
print(id(bs[:]))
xs = bs[:]
xs[1] = [9, 9, 9]
print(bs)
print(xs)
-------------
4452573000
4452573064
[1, 2, 3]
[1, [9, 9, 9], 3]

Кажется, что bs[:] делает глубокую копию xs

bs = [1, 2, 3]
print(id(bs))
print(id(bs[:])) 
xs = bs[:] = [4, 5, 6]
print(id(xs))
print(bs)
print(xs)
----------
4518600520
4518600584
4518600584
[4, 5, 6]
[4, 5, 6]

Кажется, что bs[:] делает поверхностную копию xs

bs[:] = [4, 5, 6] изменит исходный список от bs до [4, 5, 6].Но если просто сделать xs = bs[:] и xs[1] = [9, 9, 9], это не повлияет на первоначальный список bs, который по-прежнему [1,2,3]

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Присвоение из фрагмента списка всегда полных копий - то есть копирует ссылки в исходном списке.

Когда вы присваиваете список (был ли он создан путем копирования или любым другим способом)вы не изменяете объект, на который ссылаетесь - вы изменяете ссылку в списке, поэтому теперь она указывает на что-то еще.Вот что происходит в вашем первом примере:

xs[1] = [9, 9, 9]

Это меняет xs[1] на ссылку на ваш новый список [9, 9, 9].Неважно, что было источником содержимого xs.

Где это может иметь значение, если у вас есть список изменяемых объектов, и если вы используете для них методы мутации вместо переназначения:

bs = [[1], [2], [3]]
xs = bs[:] # now xs is a shallow copy of bs - it contains references to the same objects
xs[1].append(4)

Здесь xs[1] является ссылкой на тот же список, что и bs[1], поэтому вызов мутации повлияет на него независимо от того, какую ссылку вы используете для его получения.

0 голосов
/ 28 февраля 2019

Для списков и для большинства типов последовательностей извлечение фрагментов делает неглубокую копию фрагмента списка.В xs = bs[:] xs становится копией bs

Срез Назначение , с другой стороны, не делает копию нарезанного фрагмента.В bs[:] = [4, 5, 6] ни одна из частей bs не создается.Содержимое [4, 5, 6] присваивается непосредственно в bs.(Это содержимое является ссылками на объекты int, а ссылки - это то, что копируется - мы не изменяем целые числа.)


В цепочечном присваивании xs = bs[:] = [4, 5, 6] значение, присвоенное xsэто список, созданный выражением [4, 5, 6] справа, а не фрагментом bs.Назначение выполняется как

temp = [4, 5, 6]
xs = temp
bs[:] = temp

, а не

bs[:] = [4, 5, 6]
xs = bs[:]

Не выполняется извлечение фрагмента, и не создаются копии bs.


Я не знаю ни одного типа в ядре языка Python, стандартной библиотеке Python или какой-либо широко используемой сторонней библиотеке, где срез выполняет глубокое копирование.Некоторые типы, такие как viewviews и массивы NumPy, возвращают представление данных исходного объекта для извлечения фрагмента, но это даже меньше копии, чем мелкой копии.

...