You are testing the hash values for tuples. If two objects are a) equal and b) support hashing then their hash value must be the same.
This doesn't mean that they are the same object, just that they have the same hash value. Nothing more, nothing less. The hash value doesn't even have to be unique, and two objects with the same hash value don't have to be equal either; the property is not transitive.
From the __hash__
method documentation:
The only required property is that objects which compare equal have the same hash value; it is advised to somehow mix together (e.g. using exclusive or) the hash values for the components of the object that also play a part in comparison of objects.
Next, you are doing something different entirely, you are comparing if two literals in the same expression are the same. Sure they are, the compiler in this case doesn't waste memory by creating two separate objects:
>>> import dis
>>> dis.dis(compile('3430012387537 is 3430012387537', '<stdin>', 'exec'))
1 0 LOAD_CONST 0 (3430012387537)
3 LOAD_CONST 0 (3430012387537)
6 COMPARE_OP 8 (is)
9 POP_TOP
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
The LOAD_CONST
bytecode loads the same object (the constant at index 0).
That doesn't mean that every expression in the Python interpreter will reuse constants, just everything that is compiled in one block is treated this way. That means that literals in the same function could also end up reusing the same constant object though.
Bottom line is: don't use is
when you really wanted to use ==
; Python may or may not optimise memory and execution speed by reusing the same object, but not everything that is equal is going to be the same object at all times. Reserve is
for singletons only (such as None
, type objects, and explicitly created single instances).