Есть еще одна проблема, которая не указана ни в одном из существующих ответов. Python разрешено объединять любые два неизменных значения, и предварительно созданные значения малых значений не являются единственным способом, которым это может случиться. Реализация Python никогда не гарантирована , но все они делают это не более, чем просто малые int.
Во-первых, есть еще некоторые предварительно созданные такие как пустые tuple
, str
и bytes
и некоторые короткие строки (в CPython 3.6 это 256 односимвольных строк Latin-1). Например:
>>> a = ()
>>> b = ()
>>> a is b
True
Но также даже не созданные заранее значения могут быть одинаковыми. Рассмотрим следующие примеры:
>>> c = 257
>>> d = 257
>>> c is d
False
>>> e, f = 258, 258
>>> e is f
True
И это не ограничено значениями int
:
>>> g, h = 42.23e100, 42.23e100
>>> g is h
True
Очевидно, что CPython не поставляется с предварительно созданным float
для параметра 42.23e100
. Итак, что здесь происходит?
Компилятор CPython будет объединять постоянные значения некоторых известных неизменяемых типов, таких как int
, float
, str
, bytes
, в одном модуле компиляции. Для модуля весь модуль является единицей компиляции, но в интерактивном интерпретаторе каждый оператор представляет собой отдельный блок компиляции. Поскольку c
и d
определены в отдельных утверждениях, их значения не объединяются. Поскольку e
и f
определены в том же самом заявлении, их значения сливаются.
Вы можете видеть, что происходит, разобрав байт-код. Попробуйте определить функцию, которая выполняет e, f = 128, 128
, а затем называет dis.dis
на ней, и вы увидите, что существует одно постоянное значение (128, 128)
>>> def f(): i, j = 258, 258
>>> dis.dis(f)
1 0 LOAD_CONST 2 ((128, 128))
2 UNPACK_SEQUENCE 2
4 STORE_FAST 0 (i)
6 STORE_FAST 1 (j)
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
>>> f.__code__.co_consts
(None, 128, (128, 128))
>>> id(f.__code__.co_consts[1], f.__code__.co_consts[2][0], f.__code__.co_consts[2][1])
4305296480, 4305296480, 4305296480
. Вы можете заметить, что компилятор сохранил 128
как константу, даже если он фактически не используется байтовым кодом, что дает вам представление о том, как мало оптимизирует компилятор CPython. Это означает, что (непустые) кортежи на самом деле не сливаются:
>>> k, l = (1, 2), (1, 2)
>>> k is l
False
Поместите это в функцию, dis
, и посмотрите на co_consts
- есть 1
и 2
, два (1, 2)
кортежа, которые имеют одинаковые 1
и 2
, но не идентичны, и кортеж ((1, 2), (1, 2))
, который имеет два разных одинаковых кортежа.
Есть еще одна оптимизация, которую выполняет CPython: string interning. В отличие от сгибания константы компилятора, это не ограничивается литералами исходного кода:
>>> m = 'abc'
>>> n = 'abc'
>>> m is n
True
С другой стороны, он ограничен типом str
и строками типа внутреннего хранилища «ascii compact», «compact» или «legacy ready» , и во многих случаях только «ascii compact» будет интернирован.
Во всяком случае, правила для чего значения должны быть, могут быть или не могут отличаться от реализации до реализации, а также между версиями одной и той же реализации и, возможно, даже между прогонами одного и того же кода в одной и той же копии одной и той же реализации.
Возможно, стоит изучить правила для одного конкретного Python для удовольствия. Но не стоит полагаться на них в вашем коде. Единственное безопасное правило:
Или, другими словами, использовать is
только для проверки документированных синглетов (например, None
) или которые создаются только в одном месте в код (например, идиома _sentinel = object()
).