Search code examples
pythonidentityequality-operator

Does comparing using `==` compare identities before comparing values?


If I compare two variables using ==, does Python compare the identities, and, if they're not the same, then compare the values?

For example, I have two strings which point to the same string object:

>>> a = 'a sequence of chars'
>>> b = a

Does this compare the values, or just the ids?:

>>> b == a
True

It would make sense to compare identity first, and I guess that is the case, but I haven't yet found anything in the documentation to support this. The closest I've got is this:

x==y calls x.__eq__(y)

which doesn't tell me whether anything is done before calling x.__eq__(y).


Solution

  • For user-defined class instances, is is used as a fallback - where the default __eq__ isn't overridden, a == b is evaluated as a is b. This ensures that the comparison will always have a result (except in the NotImplemented case, where comparison is explicitly forbidden).

    This is (somewhat obliquely - good spot Sven Marnach) referred to in the data model documentation (emphasis mine):

    User-defined classes have __eq__() and __hash__() methods by default; with them, all objects compare unequal (except with themselves) and x.__hash__() returns an appropriate value such that x == y implies both that x is y and hash(x) == hash(y).


    You can demonstrate it as follows:

    >>> class Unequal(object):
        def __eq__(self, other):
            return False
    
    
    >>> ue = Unequal()
    >>> ue is ue
    True
    >>> ue == ue
    False
    

    so __eq__ must be called before id, but:

    >>> class NoEqual(object):
        pass
    
    >>> ne = NoEqual()
    >>> ne is ne
    True
    >>> ne == ne
    True
    

    so id must be invoked where __eq__ isn't defined.


    You can see this in the CPython implementation, which notes:

    /* If neither object implements it, provide a sensible default
       for == and !=, but raise an exception for ordering. */
    

    The "sensible default" implemented is a C-level equality comparison of the pointers v and w, which will return whether or not they point to the same object.