В этом конкретном случае, поскольку элементы ваших списков являются малыми целыми числами, Python имеет встроенный механизм для ссылки на «тот же» объект (целое число), не допуская изменения в глубоко скопированном списке, чтобы вызвать изменение в списке он был скопирован.
Вот пример с целыми числами, как ваша:
In [135]: import copy
In [136]: a1 = [1, 2, 3]
In [137]: a2 = copy.copy(a1)
In [138]: a3 = copy.deepcopy(a1)
In [139]: map(id, a1)
Out[139]: [26960216, 26960192, 26960168]
In [140]: map(id, a2)
Out[140]: [26960216, 26960192, 26960168]
In [141]: map(id, a3)
Out[141]: [26960216, 26960192, 26960168]
Таким образом, на данный момент мы можем видеть, что списки содержат целые числа, все с тем же идентификатором. Давайте изменим элемент в глубокой копии.
In [142]: a3[0] = 1000
In [143]: map(id, a1)
Out[143]: [26960216, 26960192, 26960168]
In [144]: map(id, a2)
Out[144]: [26960216, 26960192, 26960168]
In [145]: map(id, a3)
Out[145]: [39759800, 26960192, 26960168]
Теперь a3
имеет новый идентификатор для первой записи, в то время как другие списки остаются неизменными. Теперь давайте изменим первую запись мелкой копии.
In [146]: a2[0] = 1000
In [147]: map(id, a1)
Out[147]: [26960216, 26960192, 26960168]
In [148]: map(id, a2)
Out[148]: [39759200, 26960192, 26960168]
In [149]: map(id, a3)
Out[149]: [39759800, 26960192, 26960168]
Обратите внимание, как на целое число 1000, которое служит в качестве первого входа для обоих a2
и a3
, существует другое значение ID.
Причина этого в том, что среда выполнения Python фактически кэширует некоторые небольшие целые числа и другие неизменяемые объекты, что означает, что в любом месте, на которое они ссылаются, это ссылка на одно кешированное значение.
Вот a source describing it:
Текущая реализация хранит массив целых объектов для всех целых чисел от -5 до 256, при создании Int в этом диапазоне вы на самом деле просто получить назад ссылку на существующий объект , Поэтому должно быть возможно изменить значение 1. Я подозреваю, что поведение Python в этом случае не определено.:-)
Чтобы увидеть пример, где deepcopy
и copy
иметь значительно различное поведение, нам нужно что-то, где deepcopy
«s рекурсивные вызовы к copy
будет иметь значение - и это не будет для кэшируются небольшой целые числа.
Попытаемся со списком списков, и мы будем изменять содержимое, а не резко изменить то, что один из топ-большинство элементов списка относится к:
In [171]: a1 = [[1], [2], [3]]
In [172]: a2 = copy.copy(a1); a3 = copy.deepcopy(a1)
In [173]: a1
Out[173]: [[1], [2], [3]]
In [174]: a2
Out[174]: [[1], [2], [3]]
In [175]: map(id, a1)
Out[175]: [140608561277264, 140608561418040, 140608561277120]
In [176]: map(id, a2)
Out[176]: [140608561277264, 140608561418040, 140608561277120]
In [177]: a2[0][0] = 1000
In [178]: a1
Out[178]: [[1000], [2], [3]]
In [179]: a2
Out[179]: [[1000], [2], [3]]
In [180]: a3
Out[180]: [[1], [2], [3]]
In [181]: a3[1][0] = 1001
In [182]: a1
Out[182]: [[1000], [2], [3]]
In [183]: a2
Out[183]: [[1000], [2], [3]]
In [184]: a3
Out[184]: [[1], [1001], [3]]
Возможный дубликат [Почему есть нет разницы между мелкой копией и глубокой копией для списка непререкаемых] (https://stackoverflow.com/questions/23730279/why-there-is-no-difference-between-shallow-copy-and-deep-copy-for -a-list-of-immu) – chb