Python Strange error: "TypeError: object" NoneType "cannot be called"

I am implementing a simple class to represent a 2D vector. Here are the relevant bits:

class Vector: def __init__( self, x, y ): self.vec_repr = x, y def __add__( self, other ): new_x = self.x + other.x new_y = self.y + other.y return Vector( new_x, new_y ) def __getattr__( self, name ): if name == "x": return self.vec_repr[0] elif name == "y": return self.vec_repr[1] 

Later I have something like:

 a = Vector( 1, 1 ) b = Vector( 2, 2 ) a + b 

I get TypeError: 'NoneType' object is not callable . This is especially strange because the error is not flagged as any particular string, so I don't know where to look!

Very strange, so I did some experiments and found that this happens on line a+b . Also, when I rework the class as follows:

 class Vector: def __init__( self, x, y ): self.x, self.y = x, y def __add__( self, other ): new_x = self.x + other.x new_y = self.y + other.y return Vector( new_x, new_y ) 

The error disappears!

I see that there are many questions about an error like this - everything seems to be related to the fact that some function name is being rewritten somewhere in a variable, but I do not see where this is happening!

Like another key, when I change the default return type __getattr__() to something else - str, for example, the error turns into TypeError: 'str' object is not callable

Any ideas on what's going on? Is there some kind of __getattr__() behavior that I don't understand?

+8
python
source share
1 answer

The problem is that your __getattr__ nothing for attributes other than x and y , and does not raise an AttributeError attribute. Therefore, when searching for the __add__ method __add__ __getattr__ returns None and therefore your error.

You can fix this by making __getattr__ return values ​​for other attributes. In fact, you have to make sure that __getattr__ calls the method from its superclass for all attributes that are not processed. But actually __getattr__ is the wrong thing to use here. It should be used sparingly, and when there are no more obvious solutions at a higher level. For example, __getattr__ is important for dynamic __getattr__ . But in your case, the x and y values ​​are well known and well defined before the code runs.

The correct solution is to create the x and y properties and not implement __getattr__ at all.

 @property def x(self): return self.vec_repr[0] @property def y(self): return self.vec_repr[1] 
+11
source share

All Articles