There are two separate things going on here: Python stores int
literals (and other literals) as constants with compiled bytecode and small integer objects are cached as singletons.
When you run 1000 is 1000
only one such constant is stored and reused. You are really looking at the same object:
>>> 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
Here LOAD_CONST
refers to the constant at index 0; you can see the stored constants in the .co_consts
attribute of the bytecode object.
Compare this to the 1000 is 10 ** 3
case:
>>> 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
There is a peephole optimization that pre-computes expressions on constants at compile time, and this optimization has replaced 10 ** 3
with 1000
, but the optimization doesn't re-use pre-existing constants. As a result, the LOAD_CONST
opcodes are loading two different integer objects, at index 0 and 3, and these are two different int
objects.
Then there are optimisations in place where small integers are interned; only one copy of the 1
object is ever created during the lifetime of a Python program; this applies to all integers between -5 and 256.
Thus, for the 1 is 1**2
case, the Python internals use a singleton int()
object from the internal cache. This is a CPython implementation detail.
The moral of this story is that you should never use is
when you really wanted to compare by value. Use ==
for integers, always.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…