How to override comparison operators in Python

Source: Internet
Author: User

Python, like program versions, allows the behavior of operators to be customized using a scheme based on the types of objects they are applied. the precise rules and intricacies of this customization are fairly involved, though, and most people are unaware
Of their full scope. while it is sometimes valuable to be able to control the behavior of an operator to the full extent supported by python, quite often the complexity which this results in spills over into simpler applications. this is visible as a general
Tendency on the part of Python programmers to implement mizmizations which are correct for the narrow case which they have in mind at the moment, but are incorrect when considered in a broader context. since extends parts of the runtime and standard library
Rely on the behavior of these operators, this is a somewhat more egregious than the case of a similar offense made in an application-specific method, where the author can simply claim that behavior beyond what was intended is unsupported and behaves in
Undefined manner.

So, with my long-winded introduction out of the way, here are the basic rules for the customization of = ,! =, <,>, <=, And> =:

  • For all six of the above operators, if__cmp__Is defined on the left-hand argument, it is called with the right-hand argument. A result of-1 indicates the LHS is less than the RHS. A result of 0 indicates they are
    Equal. A result of 1 indicates the LHS is greater than the RHS.
  • For =, if__eq__Is defined on the left-hand argument, it is called with the right hand argument. A result of true indicates the objects are equal. A result of false indicates they are not equal. A resultNotImplementedIndicates
    That the left-hand argument doesn't know how to test for compatibility with the given right-hand argument.__eq__IsNotUsed! =.
  • For! =, The special method__ne__Is used. The rules for its behavior are similar to those__eq__, With the obvious adjustments.
  • For <,__lt__Is used. For>,__gt__. For <= and> =,__le__And__ge__Respectively.

So how shoshould these be applied? This is best explained with an example. While__cmp__Is often useful, I am going to ignore it for the rest of this post, since it is easier to get right, particle onceNotImplemented(Which I will
Talk about) is understood.

class A(object):    def __init__(self, foo):        self.foo = foo    def __eq__(self, other):        if isinstance(other, A):            return self.foo == other.foo        return NotImplemented    def __ne__(self, other):        result = self.__eq__(other)        if result is NotImplemented:            return result        return not result

That's it (because I'm not going to define the other four methods to make <,>, <=, and> = work. They follow basically the same rules__eq__And__ne__, Though). Pretty straightforward, but there are some points which are not always
Obvious:

  • __eq__Does an isinstance test on its argument. this lets it know if it is dealing with another object which is like itself. in the case of this example, I have implemented a to only know how to compare itself with other
    Instances of A. If it is called with something which is not a, it returnsNotImplemented. I'll explain what the consequences of this are below.
  • __ne__Is also implemented, but only in terms__eq__. If you implement__eq__But not__ne__, Then = and! = Will behave somewhat strangely, since the default implementation
    Of__ne__Is based on identity, not the negation of equality. Quite often a class with only__eq__Will appear to work properly! =, But it fails for varous corner-cases (for example, an object which does not compare equal
    Itself, such as Nan ).

The major remaining point isNotImplemented: What is that thing?NotImplementedSignals to the runtime that it shoshould ask someone else to satisfy the operation. In the expressiona == b, Ifa.__eq__(b)ReturnsNotImplemented,
Then Python triesb.__eq__(a). If B knows enough to return true or false, then the expression can succeed. if it doesn't, then the runtime will fall back to the built-in behavior (which is based on identity for = and! = ).

Here's another class which mizmizes equality:

class B(object):    def __init__(self, bar):        self.bar = bar    def __eq__(self, other):        if isinstance(other, B):            return self.bar == other.bar        elif isinstance(other, A):            return self.bar + 3 == other.foo        else:            return NotImplemented    def __ne__(self, other):        result = self.__eq__(other)        if result is NotImplemented:            return result        return not result

Here we have a class which can compare instances of itself to both instances itself and to instances of A. Now, what wowould happen if we weren't careful about returningNotImplementedAt the right times?

One way it might go is...

>>> class A(object):...     def __init__(self, foo):...             self.foo = foo...     def __eq__(self, other):...             return self.foo == other.foo...>>> class B(object):...     def __init__(self, bar):...             self.bar = bar...>>> A(5) == B(6)Traceback (most recent call last):  File "<stdin>", line 1, in ?  File "<stdin>", line 5, in __eq__AttributeError: 'B' object has no attribute 'foo'>>>

Another way it cocould go is...

>>> class A(object):...     def __init__(self, foo):...             self.foo = foo...     def __eq__(self, other):...             if isinstance(other, A):...                     return self.foo == other.foo...>>> class B(object):...     def __init__(self, bar):...             self.bar = bar...     def __eq__(self, other):...             if isinstance(other, A):...                     return self.bar + 3 == other.foo...             else:...                     return self.bar == other.bar...>>> print A(3) == B(0)None>>> print B(0) == A(3)True>>>

That one's maid. But here's what we get with correctNotImplementedUse:

>>> class A(object):...     def __init__(self, foo):...             self.foo = foo...     def __eq__(self, other):...             if isinstance(other, A):...                     return self.foo == other.foo...             return NotImplemented...>>> class B(object):...     def __init__(self, bar):...             self.bar = bar...     def __eq__(self, other):...             if isinstance(other, A):...                     return self.bar + 3 == other.foo...             elif isinstance(other, B):...                     return self.bar == other.bar...             else:...                     return NotImplemented...>>> print A(3) == B(0)True>>> print B(0) == A(3)True>>>

Ahh, excellent.NotImplementedHas uses for other operators in Python as well. For example, if the + override,__add__, Returns it, then__radd__Is tried on the right-hand argument. These can be useful as well, though
Equality and inequality are by far more common use cases.

If you follow these examples, then in the general case you'll find yourself with more consistently behaving objects. You may even want to implement a Mixin which provides__ne__Implementation (and one__lt__Or__gt__),
Since it gets pretty boring typing that out after a few times.

Of course, there are plenty of special cases where it makes sense to deviate from this pattern. However, they areSpecial. For most objects, This is the behavior you want.

You can read about all the gory details of Python's operator overloading system on the python Website: http://docs.python.org/ref/specialnames.hTML

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.