Deepcopy для вложенных ссылочных списков, созданных умножением списка, не работает - PullRequest
4 голосов
/ 01 февраля 2011

Как бы я ни любил Python, ссылки и глубокие копии меня иногда бесят.

Почему глубокое копирование здесь не работает:

>>> import copy
>>> a = 2*[2*[0]]
>>> a
[[0, 0], [0, 0]]
>>> b = copy.deepcopy(a)
>>> b[0][0] = 1
>>> b
[[1, 0], [1, 0]]     #should be: [[1, 0], [0, 1]]
>>> 

Я использую массив numpy как обходной путь, который мне все равно понадобится позже. Но я действительно надеялся, что, если бы я использовал Deepcopy, мне больше не пришлось бы гоняться за непреднамеренными ссылками. Есть ли еще ловушки, где это не работает?

Ответы [ 2 ]

13 голосов
/ 01 февраля 2011

Это не работает, потому что вы создаете массив с двумя ссылками на один и тот же массив.

Альтернативный подход:

[[0]*2 for i in range(2)]

Или более явный:

[[0 for j in range(2)] for i in range(2)]

Это работает, потому что он создает новый массив на каждой итерации.

Есть ли еще ловушки, где это не работает?иметь массив, содержащий ссылки, вы должны быть осторожны.Например, [Foo()] * 2 - это не то же самое, что [Foo() for i in range(2)].В первом случае создается только один объект, и массив содержит две ссылки на него.Во втором случае строятся два отдельных объекта.

7 голосов
/ 01 февраля 2011

Работает именно так, как вы ожидали.

a = 2 * [2 * [0]]

Когда вы умножаете [[0,0]] на 2 *, оба элемента нового списка будут указывать на ЖЕ [0,0] список. a[0] и a[1] - это один и тот же список, потому что копируется ссылка, а не данные (что было бы невозможно). Изменение первого элемента одного из них изменяет первый элемент другого.

copy.deepcopy правильно копирует список, сохраняя уникальные объекты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...