How to override comparison operators in Python

Jul 13, 2007 08:25


Python, like many languages, allows the behavior of operators to be ( Read more... )

Leave a comment

Comments 9

anonymous July 13 2007, 16:06:44 UTC
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.

Reply

jcalderone July 13 2007, 16:32:12 UTC
Thanks. I've corrected these two errors in the post.

Reply


anonymous July 13 2007, 16:19:03 UTC
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.

Reply

jcalderone July 13 2007, 16:36:30 UTC
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.

Reply


keturn July 13 2007, 16:47:20 UTC
NotImplemented is returned, not raised? Weird.

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

jcalderone July 13 2007, 18:24:54 UTC
__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.

Reply

ext_36920 July 23 2007, 12:25:32 UTC
NotImplementedError and NotImplemented are different things; the former is an exception, but the latter is not, so raising NotImplemented wouldn't make much sense ;)

Reply


__ne__ toidinamai July 16 2007, 15:08:19 UTC
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.

Reply

Re: __ne__ jcalderone July 16 2007, 16:53:58 UTC
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.

Reply


Leave a comment

Up