I am trying to overload several operators at once using the __getattr__
function. In my code, if I call foo.__add__(other)
it works as expected, but when I try foo + bar
, it does not. Here is a minimal example:
class Foo():
def add(self, other):
return 1 + other
def sub(self, other):
return 1 - other
def __getattr__(self, name):
stripped = name.strip('_')
if stripped in {'sub', 'add'}:
return getattr(self, stripped)
else:
return
if __name__=='__main__':
bar = Foo()
print(bar.__add__(1)) # works
print(bar + 1) # doesn't work
I realize that it would be easier in this example to just define __add__
and __sub__
, but that is not an option in my case.
Also, as a small side question, if I replace the line:
if stripped in {'sub', 'add'}:
with
if hasattr(self, name):
the code works, but then my iPython kernel crashes. Why does this happen and how could I prevent it?
__getattr__ Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self ). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
To perform operator overloading, Python provides some special function or magic function that is automatically invoked when it is associated with that particular operator. For example, when we use + operator, the magic method __add__ is automatically invoked in which the operation for + operator is defined.
This is where getattr will be so useful. Overriding getattr: If you want to do something fancy rather than your idle showing you some error, let's define getattr in the class and make it return some value. We are using this magic method to intercept the AttributeError and overloading it with our custom made defination.
It is achievable because ‘+’ operator is overloaded by int class and str class. You might have noticed that the same built-in operator or function shows different behavior for objects of different classes, this is called Operator Overloading . Attention geek!
Special symbols in Python that we use to perform various operations on objects are called Operators. The objects on which operations are performed are called Operands. We say objects because everything is an object in Python. In the above code example, + is the operator that performs the addition operation on operands num1 and num2.
This is happening because python operators use an optimization to look up the function implementing the operator. The following lines are roughly equivalent:
foo + 1
type(foo).__add__(foo, 1)
Operators are found specifically on the class object only, never on the instance.
bar.__add__(1)
calls __getattr__
to find the missing attribute on bar
. This works because it bypasses normal operator lookup procedures.
bar + 1
calls Foo.__add__(bar, 1)
followed by int.__radd(1, bar)
. The first attribute lookup fails, and the second option raises TypeError
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With