Ответ 1
Здесь происходит две отдельные вещи: Python хранит литералы int
(и другие литералы), поскольку константы с компилируемым байт-кодом и малыми целыми объектами кэшируются как одиночные.
При запуске 1000 is 1000
только одна такая константа сохраняется и повторно используется. Вы действительно смотрите на один и тот же объект:
>>> import dis
>>> compile('1000 is 1000', '<stdin>', 'eval').co_consts
(1000,)
>>> dis.dis(compile('1000 is 1000', '<stdin>', 'eval'))
1 0 LOAD_CONST 0 (1000)
3 LOAD_CONST 0 (1000)
6 COMPARE_OP 8 (is)
9 RETURN_VALUE
Здесь LOAD_CONST
относится к константе с индексом 0; вы можете увидеть сохраненные константы в атрибуте .co_consts
объекта байт-кода.
Сравните это с тегом 1000 is 10 ** 3
:
>>> compile('1000 is 10**3', '<stdin>', 'eval').co_consts
(1000, 10, 3, 1000)
>>> dis.dis(compile('1000 is 10**3', '<stdin>', 'eval'))
1 0 LOAD_CONST 0 (1000)
3 LOAD_CONST 3 (1000)
6 COMPARE_OP 8 (is)
9 RETURN_VALUE
Существует оптимизация глазок, которая предварительно вычисляет выражения для констант во время компиляции, и эта оптимизация заменила 10 ** 3
на 1000
, но оптимизация не повторяет использование ранее существовавших констант. В результате коды операций LOAD_CONST
загружают два разных целочисленных объекта с индексами 0 и 3, и это два разных объекта int
.
Затем появляются оптимизации, где маленькие целые числа интернированы; только одна копия объекта 1
когда-либо создавалась во время жизни программы Python; это относится ко всем целым числам от -5 до 256.
Таким образом, для случая 1 is 1**2
внутренности Python используют один элемент int()
из внутреннего кеша. Это деталь реализации CPython.
Мораль этой истории состоит в том, что вы никогда не должны использовать is
, когда вы действительно хотели сравнить по значению. Всегда используйте ==
для целых чисел.