Skip to content Skip to sidebar Skip to footer

Can You Impose Object Precedence For Overloaded Operators In Python?

Say I have two Python classes which both define the add and radd operator overloads, and I add one instance of one class to another instance of another class. The chosen implementa

Solution 1:

There's no builtin mechanism for defining a "precedence" as you describe. What you could do is implement the precedence checking yourself within the magic methods. That is, you could define the object's __add__ method so that it checks the "precedence" of the other object (however that's defined), and calls that object's __add__ (or __radd__) if its precedence is higher.

Note that, if you just want the LHS __add__ to defer to the RHS __radd__ you can return NotImplemented, which will essentially tell Python "act as if the __add__ method you just called didn't exist".

Here is a sketch of how this could be done with a decorator on the magic methods:

defdeco(op):
    defnewOp(self, other):
        if other.precedence > self.precedence:
            returnNotImplementedreturn op(self, other)
    return newOp

classThing(object):
    precedence = 0def__init__(self, val):
        self.val = val

    @decodef__add__(self, other):
        print"Called", self, "__add__"return self.__class__(self.val + other.val)

    def__radd__(self, other):
        print"Called", self, "__radd__"return self.__class__(self.val + other.val)

classWeak(Thing):
    precedence = 1classStrong(Thing):
    precedence = 2

This results in the Strong version always being called regardless of the order of operands, so it always returns a Strong:

>>> Weak(1) + Strong(1)
Called <__main__.Strongobject at 0x01F96BF0> __radd__
<__main__.Strongobject at 0x01F96BD0>
>>> Strong(1) + Weak(1)
Called <__main__.Strongobject at 0x01F96B90> __add__
<__main__.Strongobject at 0x01F96250>

Solution 2:

Python will use __radd__ if __add__ is not implemented on the first of the items using the + operator.

foo + bar

will attempt to use foo's __add__ operator on the other, bar. If that is not implemented, it will call bar's __radd__.

classFoo(object):
    passclassBar(object):
    def__radd__(self, other):
        print('Bar.__radd__ was called!')

>>> foo = Foo()
>>> bar = Bar()
>>> foo + bar
Bar.__radd__ was called!

And when Foo has __add__ it gets precedence:

classFoo(object):
    def__add__(self, other):
        print('Foo.__add__ was called!')

>>> foo = Foo()
>>> foo + bar
Foo.__add__ was called!

You cannot force Python to do anything special if both are implemented, the order of precedence is predefined. You can check for the other's existence however:

classFoo(object):
    def__add__(self, other):
        ifhasattr(other, '__radd__'):
            return other.__radd__(self)
        else:
            print('Foo.__add__ was called!')

>>> foo = Foo()
>>> foo + bar
Bar.__radd__ was called!

Post a Comment for "Can You Impose Object Precedence For Overloaded Operators In Python?"