Bob Fang
Bob Fang

Reputation: 7411

Does __ne__ use an overridden __eq__?

Suppose I have the following program:

class A(object):                                                                                                                                                                                                                                                              
    def __eq__(self, other):
        return True

a0 = A() 
a1 = A() 
print a0 != a1

If you run it with Python the output is True. My question is

  1. the __ne__ method is not implemented, does Python fall on a default one?
  2. if Python fall on a default method to determine whether two objects are equal or not, shouldn't it call __eq__ and then negate the result?

Upvotes: 6

Views: 348

Answers (2)

zuo
zuo

Reputation: 176

Quick answer

[if] the __ne__ method is not implemented, does Python fall on a default one?

Generally speaking, yes, it does - but the point is: what the behavior of the default __ne__ is. And that depends on the version of Python (please read on).

if Python fall on a default method to determine whether two objects are equal or not, shouldn't it call __eq__ and then negate the result?

  • Python 2.x: it does not. On self != other, if no custom __ne__ is provided by self or other then only object identities are checked (so the effective behavior is equivalent to self is not other).
  • Python 3.x: indeed, the default implementation of __ne__ calls __eq__ and negates the result (but on the technical level there are some subtleties, please read on).

Interlude: what happens when __ne__ returns NotImplemented

Each of the Python's “rich comparison” methods, including __ne__, can either give a resolute answer (typically: True or False) or say I don't know! by returning a special singleton object, NotImplemented (warning: not to be confused with NotImplementedError!).

On self != other, first self.__ne__(other) is called, and if it returns NotImplemented then Python tries other.__ne__(self) (however, if the type of other is a subclass of the type of self but not the same type then the order is reverse: other.__ne__(self) is called first, and only if it returns NotImplemented the self.__ne__(other) call is tried). If both calls returned NotImplemented then Python falls back to an object-identity-based check (self is not other).

The behavior related to == and __eq__ is analogous.

That's what is referred to by the docs in the fragment:

__eq__() and __ne__() are their own reflection

Note: this fragment should be understood as: __eq__() is its own reflection and __ne__() is its own reflection (each on its own, separately).

Python 2.x behavior

As Ami Tavory wrote, when it comes to the standard behavior and default implementations, there are no implied relationships between __ne__ and __eq__.

Python 3.x behavior

From the docs:

For __ne__(), by default it delegates to __eq__() and inverts the result unless it is NotImplemented.

In other words, the behavior of object.__ne__ is (roughly) equivalent to:

def __ne__(self, other):
    res = self.__eq__(other)
    if res is NotImplemented:
        return NotImplemented
    return not res

Of course, object.__ne__ can be shadowed by another implementation provided by a subclass. That's why, when you implement a subclass of, for example, dict, if you want to provide your customized __eq__ you also need to provide __ne__ (whose implementation can be just as in the above code snippet, or even shorter: return object.__ne__(self, other)).

Upvotes: 1

Ami Tavory
Ami Tavory

Reputation: 76366

From the docs:

There are no implied relationships among the comparison operators. The truth of x==y does not imply that x!=y is false. Accordingly, when defining __eq__(), one should also define __ne__() so that the operators will behave as expected.

Upvotes: 12

Related Questions