Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading operators using __getattr__ in Python

Tags:

python

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?

like image 808
drmaettu Avatar asked Oct 14 '21 17:10

drmaettu


People also ask

What does __ Getattr __ do in Python?

__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.

How to overload operators in Python?

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.

What is the use of getattr in Python?

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.

Why ‘+’ operator is overloaded?

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!

What are operators in Python?

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.


1 Answers

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.

like image 122
Mad Physicist Avatar answered Sep 28 '22 06:09

Mad Physicist