После E0_copy = list(E0), я думаю, E0_copy это глубокая копия E0 поскольку id(E0) не равно id(E0_copy). Затем я изменяю E0_copy в цикле, но почему после этого E0 не то же самое?
E0_copy это не глубокое копирование. Вы не создаете глубокое копирование с помощью list(). (Оба list(...) и testList[:] являются мелкими копиями, так же как testList.copy().)
>>> a = [[1, 2, 3], [4, 5, 6]] >>> b = list(a) >>> a [[1, 2, 3], [4, 5, 6]] >>> b [[1, 2, 3], [4, 5, 6]] >>> a[0][1] = 10 >>> a [[1, 10, 3], [4, 5, 6]] >>> b # b changes too -> Not a deepcopy. [[1, 10, 3], [4, 5, 6]]
Теперь посмотрите на deepcopy операцию
>>> import copy >>> b = copy.deepcopy(a) >>> a [[1, 10, 3], [4, 5, 6]] >>> b [[1, 10, 3], [4, 5, 6]] >>> a[0][1] = 9 >>> a [[1, 9, 3], [4, 5, 6]] >>> b # b doesn't change -> Deep Copy [[1, 10, 3], [4, 5, 6]]
Чтобы объяснить, list(...) не создает рекурсивно копии внутренних объектов. Он создает копию только самого внешнего списка, продолжая ссылаться на те же внутренние списки, следовательно, когда вы изменяете внутренние списки, изменение отражается как в исходном списке, так и в мелкой копии. Вы можете увидеть, что неглубокое копирование ссылается на внутренние списки, проверив это id(a[0]) == id(b[0]) где b = list(a).
Ответ 2
В Python есть модуль под названием copy с двумя полезными функциями:
import copy copy.copy() copy.deepcopy()
copy() это функция неглубокого копирования. Если заданный аргумент представляет собой составную структуру данных, например, список, то Python создаст другой объект того же типа (в данном случае, новый список), но для всего, что находится внутри старого списка, копируется только их ссылка. Представьте это следующим образом:
newList = [elem for elem in oldlist]
Интуитивно мы могли бы предположить, что deepcopy() будет следовать той же парадигме, и единственная разница заключается в том, что для каждого элемента мы будем рекурсивно вызывать deepcopy, (точно так же, как ответ mbguy)
но это неправильно!
deepcopy() фактически сохраняется графическая структура исходных составных данных:
a = [1,2] b = [a,a] # there's only 1 object a c = deepcopy(b)
# check the result c[0] is a # False, a new object a_1 is created c[0] is c[1] # True, c is [a_1, a_1] not [a_1, a_2]
Это сложная часть: в процессе deepcopy() используется хэш-таблица (словарь в Python) для сопоставления каждого старого объекта ref с каждым новым объектом ref, что предотвращает ненужные дублирования и, таким образом, сохраняет структуру скопированных составных данных.