我正在实现一个简单的类来表示2D矢量。以下是相关内容:
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]
稍后,我有类似的事情:
a = Vector( 1, 1 )
b = Vector( 2, 2 )
a + b
我得到TypeError: 'NoneType' object is not callable
。这特别奇怪,因为错误没有标记为在任何特定的行上,所以我不知道在哪里看!
非常奇怪,所以我做了一些实验,发现它发生在a+b
行上。另外,当我重新上课时,如下:
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 )
错误消失了!
我看到有很多关于类似于此的错误的问题 - 所有似乎都涉及某个函数名称被某个变量覆盖,但我看不出这发生了什么!
作为另一个线索,当我将__getattr__()
的默认返回类型更改为其他内容时 - 例如str - 错误变为TypeError: 'str' object is not callable
关于发生了什么的任何想法?是否有一些我不理解的__getattr__()
行为?
答案 0 :(得分:11)
问题是您的__getattr__
不会为x
和y
以外的属性返回任何内容,也不会引发AttributeError。因此,当查找__add__
方法时,__getattr__
会返回None
,从而返回错误。
您可以通过为其他属性返回__getattr__
值来解决此问题。实际上,您必须确保__getattr__
从其超类调用未处理的所有属性的方法。但真的__getattr__
在这里使用是错误的。它应该谨慎使用,并且当没有更明显的,更高级别的解决方案可用时。例如,__getattr__
对动态调度至关重要。但在您的情况下,x
和y
值在代码运行之前是众所周知且定义良好的。
正确的解决方案是制作x
和y
属性,而不是实现__getattr__
。
@property
def x(self):
return self.vec_repr[0]
@property
def y(self):
return self.vec_repr[1]