Почему глубокая копия списка целых чисел возвращает те же самые целые числа в памяти?

Я понимаю различия между мелкой копией и глубокой копией, как я узнал в классе. Однако следующее не имеет смысла

import copy

a = [1, 2, 3, 4, 5] 

b = copy.deepcopy(a)

print(a is b)
print(a[0] is b[0])
----------------------------
~Output~
>False
>True
----------------------------

Не следует print(a[0] is b[0]) оценивать значение False, поскольку объекты и их составляющие элементы воссоздаются в другом месте памяти в глубокой копии? Я просто тестировал это, так как мы обсуждали это в классе, но он, похоже, не работает.

Ответ 1

В другом ответе было предложено, что это может быть связано с тем, что Python интернировал объекты для маленьких целых чисел. Хотя это правда, это не то, что вызывает такое поведение.

Давайте посмотрим, что происходит, когда мы используем большие целые числа.

> from copy import deepcopy
> x = 1000
> x is deepcopy(x)
True

Если мы покопаемся в модуле copy то обнаружим, что вызов deepcopy с атомарным значением откладывает вызов функции _deepcopy_atomic.

def _deepcopy_atomic(x, memo):
    return x

Так что на самом деле происходит то, что deepcopy не будет копировать неизменное значение, а только вернет его.

В качестве примера это относится к int, float, str, function и многим другим.

Ответ 2

Причиной такого поведения является то, что Python оптимизирует небольшие целые числа, поэтому они фактически не находятся в разных ячейках памяти. Проверьте id 1, они всегда одинаковы:

>>> x = 1
>>> y = 1
>>> id(x)
1353557072
>>> id(y)
1353557072

>>> a = [1, 2, 3, 4, 5]
>>> id(a[0])
1353557072

>>> import copy
>>> b = copy.deepcopy(a)
>>> id(b[0])
1353557072

Ссылка из Целых объектов:

Текущая реализация сохраняет массив целочисленных объектов для всех целых чисел между -5 и 256, когда вы создаете int в этом диапазоне, вы фактически просто возвращаете ссылку на существующий объект. Поэтому должно быть возможно изменить значение 1. Я подозреваю, что поведение Python в этом случае undefined.: -)