Кажется, что нарезка массива делает глубокую копию?
Предполагается, что нарезка в python делает мелкую копию. Тем не менее, когда я запускаю следующее:
cur = [[0] * (2) for _ in xrange(2)]
cur2 = [row[:] for row in cur]
cur2[0][0] = "foo"
print(cur)
print(cur2)
Я получил:
[[0, 0], [0, 0]] # cur
[['foo', 0], [0, 0]] # cur2
что создает впечатление, что это глубокая копия.
У меня два вопроса: 1) Что здесь происходит? Это глубокая или мелкая копия? 2) Что с этим синтаксисом делает его намного быстрее, чем copy.deepcopy? Например, это что-то с тем, как python управляет памятью?
2 ответа
Вы делаете неглубокие копии внутренних списков (то есть строк), которые фактически совпадают с глубокой копией внешнего списка, если внутренние списки являются просто списками int
объекты.
Вы по существу реализовали функцию глубокого копирования для особого случая списка списков целых чисел.
С помощью copy.deepcopy
будет медленнее, потому что эта функция должна будет исследовать и кэшировать все идентификаторы объектов, включая int
объекты. Ваш фрагмент не делает этого, но в данном конкретном случае это не имеет значения (обратите внимание, маленький int
объекты кэшируются на уровне интерпретатора, они по сути являются одиночными, и в любом случае, int
объекты являются неизменяемыми, поэтому их вообще не нужно копировать).
Вот ссылка на copy
Исходный код модуля, если вы хотите увидеть, что именно входит в общую глубокую копию.
Я думаю, что вы неправильно понимаете, что такое мелкая и глубокая копия.
Мелкая копия копирует структуру коллекции (по существу, области памяти), тогда как глубокая копия дублирует все (как в реальных данных) в памяти.
Здесь вы формируете новый список копий каждого из подсписков из исходного 2d-списка - таким образом, получается совершенно новый список без связей с исходным списком - поэтому вы сделали глубокую копию.
Если вместо этого вы должны сделать: cur[:]
вы просто скопируете внешний список, который содержит те же ссылки на внутренний список - следовательно, мелкую копию.
В вашем случае, поскольку все места в памяти разные, изменение одного элемента не влияет на оригинал, но если вы просто сделаете cur[:]
, тогда внутренние строки будут ссылаться на те же места в памяти, поэтому изменение элементов из любого списка повлияет на другой список.