Search code examples
pythonoptimizationimmutabilityinequality

Apart from trivial data types, then are python immutable object ids the same?


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?


Solution

  • 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 bools. 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.