Раньше я показывал что-то вроде print(5 is 7 - 2, 300 is 302 - 2)
в своих выступлениях на Python, когда говорил о некоторых мелочах Python. Сегодня я понял, что этот пример дает неожиданный (для меня) результат при запуске в Python 3.7.
Мы знаем, что числа от -5 до 255 кэшируются внутри Python 3. docs — PyLong_FromLong, который также можно найти в более ранних документах по API.
Оператор is
(как описано в документах Python 3 docs — is operator ) проверяет идентичность объекта, т. е. использует функцию id()
, чтобы определить это, и возвращает True
, когда значения совпадают.
Функция id()
гарантированно возвращает уникальное и постоянное значение для объекта в течение его жизни (также описано в документах Документация по Python 3 — id()).
Все эти правила дают вам следующие результаты (как известно многим программистам Python):
Питон 2.7:
>>> print(5 is 7 - 2, 300 is 302 - 2)
True False
Питон 3.6:
>>> print(5 is 7 - 2, 300 is 302 - 2)
True False
Однако Python 3.7 ведет себя иначе:
>>> print(5 is 7 - 2, 300 is 302 - 2)
True True
Я пытался понять, почему, но пока не нашел подсказок в исходниках Python...
id(302 - 2)
всегда дает другое значение, поэтому мне интересно, почему 302 - 2 is 300
дает True
. Как оператор is
узнает, что значения совпадают? Это как-то перегружено для целочисленных сравнений в Python 3.7?
>>> id(300)
140059023515344
>>> id(302 - 2)
140059037091600
>>> id(300) is id(302 - 2)
False
>>> 300 is 302 - 2
True
>>> id(300) == id(302 -2)
True
>>> id(302 - 2)
140059037090320
>>> id(302 - 2)
140059023514640
import dis; dis.dis.dis(compile('print(5 is 7 - 2, 300 is 302 - 2)', '', 'single'))
, чтобы узнать, как это повлияет на ваш образец. Обратите особое внимание на номер индекса после каждого кода операцииLOAD_CONST
. - person Martijn Pieters   schedule 03.04.2019