In your first class definition there is a typo. It should be self.foo = foo instead of == in A.__init__. Also the runtime doesn't raise a NotImplementedError if both methods return NotImplemented, it just returns False.
In the expression a == b, if a.__eq__(b) returns NotImplemented, then Python tries b.__eq__(a). If b knows enough to return True or False, then the expression can success.
There is another magic thing that it happening here: If b's class is a subclass of a's, then b.__eq__(a) is called first! I think this rule is the same for all other operators.
Thanks for pointing this out. I almost made B a subclass of A in the original post, but I decided that would have made it too hard to follow. :) It's a good rule to know, though, since it means derived classes get the first chance to define how the operation is performed.
Since the __ne__ implementation is always so stupid, why not define __cmp__ instead? I suppose "Called by comparison operations if rich comparison is not defined." means that it could fail if you unwittingly have the other operations defined somewhere else in your inheritance tree?
__cmp__ is definitely much simpler. Pushing people to use it more frequently and avoid __xy__ might make another good post :) The one disadvantage of __cmp__ is that if you only care about == and !=, it's still very difficult to avoid implementing < and >. In fact, off the top of my head, I can't think of a __cmp__ implementation which would work for _only_ implementing == and !=. This might not be of much practical consequence (after all, object implements < and >, and it just does so in a pseudo-random way), but it's a bit annoying.
NotImplementedError and NotImplemented are different things; the former is an exception, but the latter is not, so raising NotImplemented wouldn't make much sense ;)
There is another thing regarding your implementation of __ne__: Only in old style classes special attributes like __eq__ are looked up through the object itself. For objects of new style classes they are always looked up only through the class. As your classes are new style self.__eq__(other) could be written more correctly as type(self).__eq__(self, other).
At first I thought one could simply return not (self == other) but there may be some rare cases where it might be advisable to do something different for __ne__ than simply returning the negation of __eq__ although I can't think of any right now.
Yes, that's true. In most cases, self.__eq__ will work just fine. For a general mixin, you might want to follow the same rules as are implicitly used, indeed.
You might not want to just use not (self == other), since that might end up being satisfied by other.__eq__, which precludes the possibility of other.__ne__ being used, which would be somewhat less surprising, if it is also defined.
Comments 9
Reply
Reply
There is another magic thing that it happening here: If b's class is a subclass of a's, then b.__eq__(a) is called first! I think this rule is the same for all other operators.
Reply
Reply
Since the __ne__ implementation is always so stupid, why not define __cmp__ instead? I suppose "Called by comparison operations if rich comparison is not defined." means that it could fail if you unwittingly have the other operations defined somewhere else in your inheritance tree?
Reply
Reply
Reply
At first I thought one could simply return not (self == other) but there may be some rare cases where it might be advisable to do something different for __ne__ than simply returning the negation of __eq__ although I can't think of any right now.
Reply
You might not want to just use not (self == other), since that might end up being satisfied by other.__eq__, which precludes the possibility of other.__ne__ being used, which would be somewhat less surprising, if it is also defined.
Reply
Leave a comment