Кажется, что нарезка массива делает глубокую копию?

Предполагается, что нарезка в 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[:], тогда внутренние строки будут ссылаться на те же места в памяти, поэтому изменение элементов из любого списка повлияет на другой список.

Другие вопросы по тегам