I was introducing is operator to my students when I noticed that there is an inconsistency in its behavior between python (v3.6 and older) and (v3.7).
Launch a python shell and run:
5/2 is 2.5
Or:
(1, 2, 3) is (1, 2, 3)
in v3.6.X you get False for both, but in v3.7 they turn out to be True.
My expectation was that the result should be True as I thought immutable numeric objects (or a tuple of them) have just one instance.
It seems that at least my thought was not right in the previous versions of Python.
Does anyone know what changes have been made which explains this new behaviour?
I'm not sure about reasons and source for this, but my guess is that this has something to do with in-line optimizations.
If you'll assign variable for this values, identity check will result in False, same as before.
>>> 5/2 is 2.5
True
>>> a = 5/2
>>> a is 2.5
False
Interesting note on new folding optimisation. As python is "all runtime", there's no way to optimize some things ahead, but it tries hard, parsing as much scope as it can:
>>> a = 3.14
>>> b = 3.14
>>> a is b
False
>>> a = 3.14; b = 3.14
>>> a is b
True
My expectation was that the result should be True as I thought immutable numeric objects (or a tuple of them) have just one instance.
That expectation is questionable - there's no such thing guaranteed by the Python language.
is is a quite tricky operator because you really need to know when it's appropriate to use it.
For example:
>>> 5 / 2 is 2.5
>>> (1, 2, 3) is (1, 2, 3)
These are not appropriate uses of is in the general case. They may be appropriate if you want to check what line/function optimizations (interning) Python is doing but I guess that wasn't the desired use-case here.
is should only be used if you want to compare to constants (that are guaranteed to only have one instance)! The guaranteed built-in constants are:
NoneNotImplementedEllipsis (also known as ...)TrueFalse__debug__Or your own constant-like instances:
_sentinel = object()
def func(a=_sentinel):
return a is _sentinel
Or when you explicitly assign variables to a new name:
a = b
a is b # <- that's expected to be True
Does anyone know what changes have been made which explains this new behaviour?
Probably the peep-hole optimizer now optimizes more cases (tuples and mathematical expressions). For example "AST-level Constant folding" (https://bugs.python.org/issue29469) has been added in CPython 3.7 (I intentionally wrote CPython here because it's nothing that has been added to the Python 3.7 language specification).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With