inconsistency in "is" behavior over immutable objects in python 3.6 and older vs 3.7
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
and get $2,000 discount on your first invoice
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Hypnotic Orient Looping
--
Chapters
00:00 Inconsistency In &Quot;Is&Quot; Behavior Over Immutable Objects In Python 3.6 And Older Vs 3.7
00:49 Accepted Answer Score 5
01:23 Answer 2 Score 1
02:03 Answer 3 Score 2
03:05 Answer 4 Score 2
04:41 Thank you
--
Full question
https://stackoverflow.com/questions/5459...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #python3x #internals
#avk47
ACCEPTED ANSWER
Score 5
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
ANSWER 2
Score 2
I believe that this behavior is due moving the Constant folding from the peephole optimizer (compile time operation) to the new AST optimizer (run time operation), which as it's also mentioned in https://docs.python.org/3/whatsnew/3.7.html#optimizations is now able to perform optimizations more consistently. (Contributed by Eugene Toder and INADA Naoki in bpo-29469 and bpo-11549.)
Re:
My expectation was that the result should be True as I thought immutable numeric objects (or a tuple of them) have just one instance.
Immutability is not strictly the same as having an unchangeable value. Before you call an object mutable or immutable it's an object and objects in Python are created at run time. So there's no reason to connect mutability to object creation and identity. There are, however, some exceptions like this one or small object interning in both previous and current versions which, mostly for the sake of optimization, this rule (object creation at run time) gets manipulated. Read https://stackoverflow.com/a/38189759/2867928 for more details.
ANSWER 3
Score 2
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).
ANSWER 4
Score 1
Why should immutable objects that are the same occupy the same instance?
When using is in python, you are essentially asking if a and b occupy the same piece in memory. If you think of a and b as immutable literals, it's not like python has a specific space to save every type of immutable literal. It's pure chance that it returned true in this instance and entirely possible it will return false if you choose a different literal. Take a look at this:
>>> a = "wtf"
>>> b = "wtf"
>>> a is b
True
>>> a = "wtf!"
>>> b = "wtf!"
>>> a is b
False
>>> a, b = "wtf!", "wtf!"
>>> a is b
True
If you want to avoid this, do not use is on things you didn't explicitly save into memory.