the behavior of is seems pretty hard to predict
>>> 3.1 is 3.1
True
>>> a = 3.1
>>> a is 3.1
False >>> 3.1 is 3.1
True
>>> a = 3.1
>>> a is 3.1
False >>> a = 'hn'
>>> a is 'hn'
True
>>> a = ''.join(['h', 'n'])
>>> a is 'hn'
False
>>> a
'hn'
>>> a = 'h' + 'n'
>>> a is 'hn'
True
Edit: found another interesting case >>> a = 1
>>> b = 1
>>> a is b
True
>>> a = 500
>>> b = 500
>>> a is b
False a = 500
b = 500
a is b
will give `True`. But the REPL forces each line to compile separately and CPython won't cache across them. However, there's a global cache for integers less than 256 so in that case they're `is`-equivalent even in the REPL.For inequivalent values or `True`, `False` and `None`, the result is defined. Identity is also preserved across assignment. For everything else, the answer is "whatever the runtime feels like". PyPy, for instance, will always say True for integers and floats.
It's not just hard to predict - it's inherently unpredictable. The runtime gets free reign as long as you can't prove that it's lying.