为什么具有重新定义的__getattr __()的对象会引发TypeError?

时间:2019-03-01 16:57:32

标签: python python-2.7 typeerror setattr

这是代码

class MyTest: 
    def __init__(self):
         pass

    def __getattr__(self, attr):
        pass
t = MyTest()
print 'my test object: %r' %t

因此,当我只想查看对象是否存在时,打印会触发TypeError: 'NoneType' object is not callable。 授予此代码不是很有用。但是我在大型代码库中有一个像这样的存根类,所以我做了

if module and module.class and module.class.propery:
   # do something with that property
 ...

并得到一个Type Error: 'NoneType' object is not callable,但该行什么也没叫!我猜想python正在幕后隐式调用某些函数。

奇怪的是,如果类继承自Object

,则不会发生这种情况

这是怎么回事?

2 个答案:

答案 0 :(得分:3)

在旧式类中,__getattr__用于更多种类的属性访问,包括魔术方法。 %运算符试图调用t.__repr__()以填充%r占位符,但是t.__repr__t.__getattr__('__repr__')求值,它返回{{1} }。

None情况下,调用了另一种魔术方法,但是出现了相同的问题。

if

使用新型类,仅当无法通过常规方法找到属性(检查实例或实例MRO中任何类的>>> class Foo: ... def __getattr__(self, attr): ... print(attr) ... >>> f = Foo(): >>> if f: ... pass __nonzero__ Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'NoneType' object is not callable 属性)时才调用__getattr__ )。

__dict__

>>> class Foo(object): ... def __init__(self): ... self.x = 3 ... def __getattr__(self, attr): ... print(attr) ... >>> f = Foo() >>> if f: ... pass ... >>> f.x 3 >>> f.y y 情况下,if f本身未实现f__nonzero__,其父项__len__也未实现,但是在这种情况下,不使用属性;实际上使用了object是对象的事实。在f中,在实例的属性dict中找到f.x,因此直接返回其值。只有x(没有由yfFoo定义的)才能调用对object的调用。

答案 1 :(得分:2)

在python 2中,使用旧式类,当您尝试在对象上调用__repr__(在打印时)时,就会调用__getattr__

由于您猛烈地使用了此方法,因此它会返回None,而python会尝试调用None(因为它期望返回一个方法)

尝试致电object.__getattr__,它将起作用:

class MyTest:
    def __init__(self):
         pass

    def __getattr__(self, attr):
        print(attr)   # so we see why getattr is called
        return object.__getattr__(self,attr)  # so it doesn't crash (neither it is useful...)

t = MyTest()
print ('my test object: %r' %t)

打印:

__repr__
my test object: <__main__.MyTest instance at 0x00000000031B3808>

这是特定的python 2 /旧式对象问题。 Python 3或新型对象的行为不同