2011-07-31 54 views
8

我正在实现一个简单的类来表示一个2D矢量。这里的是相关的位:Python奇怪的错误:“TypeError:'NoneType'对象不可调用”

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。此外,当我重新班级如下:

​​

错误消失!

我看到有很多类似这样的错误的问题 - 所有似乎都涉及到某个函数名被某个变量覆盖的地方,但是我不知道这是怎么回事!

至于另一条线索,当我改变的__getattr__()默认返回类型别的东西 - 海峡,例如 - 错误摇身一变TypeError: 'str' object is not callable

任何想法,这是怎么回事?有没有我不明白的__getattr__()的一些行为?

回答

11

问题是您的__getattr__不会为xy以外的属性返回任何内容,也不会引发AttributeError。因此,当__add__方法查找时,__getattr__返回None,因此您的错误。

您可以通过为其他属性设置__getattr__返回值来解决此问题。实际上,您必须确保__getattr__针对所有未处理的属性从其超类中调用该方法。但真的__getattr__是在这里使用的错误的东西。它应该谨慎使用,并且当没有更明显的,更高级别的解决方案可用时。例如,__getattr__对于动态调度是必不可少的。但在你的情况下,xy值是众所周知的,并且在代码运行之前已经很好地定义了。

正确的解决方案是使xy属性,而不是执行__getattr__根本。

@property 
def x(self): 
    return self.vec_repr[0] 

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

和公正的全貌,它试图调用'__coerce__' –

+0

@yi_H我不熟悉'__coerce__',但我能猜出它会做什么,以及为什么它会被称为! –

+0

哦。哇谢谢。我认为它在__getattr __()时没有找到其他地方的属性。好吧,这非常令人尴尬。 – Slubb