For immutable data types, Python does not guarantee that two constructions result in two different objects; as such, 1+1 is 2
may or may not return True
. For sure, mutable types do result in separate objects: [] is []
will always return False
.
From https://docs.python.org/3/reference/datamodel.html#objects-values-and-types:
Types affect almost all aspects of object behavior. Even the importance of object identity is affected in some sense: for immutable types, operations that compute new values may actually return a reference to any existing object with the same type and value, while for mutable objects this is not allowed. E.g., after a = 1; b = 1, a and b may or may not refer to the same object with the value one, depending on the implementation, but after c = []; d = [], c and d are guaranteed to refer to two different, unique, newly created empty lists. (Note that c = d = [] assigns the same object to both c and d.)
>>> "abc" is "abc"
True
>>> [] is []
False
>>> 1 + 1 is 2
True
Now, apart from the trivial types int
, float
, bool
, string
, I would expect tuple
and frozenset
to show the same behavior.
But I find no cases where they do:
>>> {1, 2} is {1, 2}
False
>>> (1, ) is (1, )
False
Are there any implementation s that do yield the same id for separate immutable objects?
All of the is
equality for these objects are resultant from interpreter tricks (that are not apart of the language spec AFAIK but consequences of CPython)
For example (with int
).
The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object.
So it should be possible to change the value of 1. I suspect the behavior of Python in this case is undefined. :-)
And for strings, python does interning
. bool
is a subclass of int
(issubclass(bool, int)
) which explains shared id
for bool
s. AFAIK, floats (aside from literals in 3.8) never return True for is
equality.
In python3.8, (1,) is (1,)
is actually True
due to changes in literal evaluation.
>>> (1,) is (1,)
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
True
Along with a warning for is
being used for literals. However, assigning variables and performing the comparison is False (as expected).
Note that tuple() is tuple()
and frozenset() is frozenset()
both return True. However, their mutable counterparts (list
and set
) do not have this property.