Can You Impose Object Precedence For Overloaded Operators In Python?
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?"