Подтвердить что ты не робот

Почему Python обрабатывает "1 1 ** 2" по-другому, чем "1000 - 10 ** 3"?

Вдохновленный этим вопросом о кешировании небольших целых чисел и строк, я обнаружил следующее поведение, которое я не понимаю.

>>> 1000 is 10**3
False

Я думал, что понял это поведение: 1000 - это большой, чтобы быть кешированным. 1000 и 10 ** 3 точки на 2 разных объекта. Но у меня было это неправильно:

>>> 1000 is 1000
True

Итак, возможно, Python рассматривает вычисления иначе, чем "нормальные" целые числа. Но это предположение также неверно:

>>> 1 is 1**2
True

Как объяснить это поведение?

4b9b3361

Ответ 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, когда вы действительно хотели сравнить по значению. Всегда используйте == для целых чисел.