This is due to a simple optimization at the bytecode compilation stage; if the same constant appears in the same code more than once, it is created only once, and each use of the constant will refer to the same instance.
We can investigate the bytecode with the dis module:
>>> import dis
>>> dis.dis('l = 40000\nm=40000')
1 0 LOAD_CONST 0 (40000)
2 STORE_NAME 0 (l)
2 4 LOAD_CONST 0 (40000)
6 STORE_NAME 1 (m)
8 LOAD_CONST 1 (None)
10 RETURN_VALUE
>>> dis.dis('l = 40000\nm=40001')
1 0 LOAD_CONST 0 (40000)
2 STORE_NAME 0 (l)
2 4 LOAD_CONST 1 (40001)
6 STORE_NAME 1 (m)
8 LOAD_CONST 2 (None)
10 RETURN_VALUE
Note that in the first case where both constants are 40000
, the two LOAD_CONST
operations both load constant #0, but in the second case, 40000
is constant #0 and 40001
is constant #1.
Also, you will usually get different results if you do this on separate lines in the REPL, since each line in the REPL is compiled and executed as a separate code object, so they cannot share constants:
>>> l = 50000
>>> m = 50000
>>> id(l)
140545755966480
>>> id(m)
140545755966448
But if you do both in one line in the REPL, the same instance of the constant is used again, because it's just one line compiled to one code object, so the constant can be shared:
>>> p = 60000; q = 60000
>>> id(p)
140545755966576
>>> id(q)
140545755966576