2

I have a containery object something like this:

class foo(object):
  def __init__(self,value):
    self.value = value
  def __eq__(self,other):
    return self.value == other

Which I can use like this:

>>> var = foo(4)
>>> var == 4
True
>>> var == 3
False
>>> # So far so good
>>> var == foo(4)
True
>>> var == foo(3)
False
>>> # Huh

My question is: what is happening that allows this to magically "just work"? How does Python bind the == operator inside __eq__ so that the value member of both sides is compared?

3

1 Answer 1

6

If an __eq__ method returns NotImplemented for a given argument, Python will try the same test in reverse. So x == y will try x.__eq__(y) first, if that returns the NotImplemented singleton, y.__eq__(x) is tried.

This applies to the comparison inside your __eq__ method as well; you are essentially comparing:

self.value == other

which is:

4 == other

which is:

4.__eq__(other)

which returns NotImplemented:

>>> var = foo(4)
>>> (4).__eq__(var)
NotImplemented

So Python tries other.__eq__(4) instead, which returns True.

Sign up to request clarification or add additional context in comments.

14 Comments

My local implementation of Python gives AttributeError: 'int' has no attribute '__eq__'. I guess any exception prompts the reversal of the comparison? Do similar things happen if a class implements __gt__ but not __lt__?
So when comparing var == foo(4) this get's reduced to var.value == foo(4) Which should raise a notimplemented error. Does it then try the reverse as foo(4) == var.value or foo(4) == var? would it try the second if the first also raised a notimplemented error?
Note that things are slightly different for methods which have reflected bindings in the object model -- e.g. __add__. In that case, I believe the call order is __add__(x, y) -> __radd__(x, y)
@M4rtini: var.__eq__(foo(4)) is called, this then executes another comparison, var.other == foo(4). Python tries that separately, so first var.other.__eq__(foo(4)) returning NotImplemented, then foo(4).__eq__(var.other), returning True. So the outermost var.__eq__(foo(4)) call does not return NotImplemented, it returns True.
@M4rtini: Yes, if the foo.__eq__() method itself explicitly returns NotImplemented then other.__eq__() will be tried.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.