为什么重新定义 __getattr__() 的对象会抛出 TypeError?

Why does an object with redefined __getattr__() throws TypeError?

这是代码

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 而我只想查看对象是否存在。 当然,此代码不是很有用。但是我在大型代码库中有一个像这样的存根 class 所以我做了

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

并得到一个 Type Error: 'NoneType' object is not callable 但该线路没有调用任何东西!我猜 python 正在幕后隐式调用一些函数。

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

,则不会发生这种情况

怎么回事?

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

因为你猛烈地破坏了这个方法,它 returns 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 个或新式对象的行为不同

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

if的情况下,调用了不同的魔术方法,但出现了同样的问题。

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

使用新样式 class,仅当无法通过正常方法找到属性时才调用 __getattr__(检查实例或任何实例的 __dict__ 属性class 在实例的 MRO 中)。

>>> 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 是一个对象。在f.x中,x是在实例的属性dict中找到的,所以直接返回它的值。只有未由 fFooobject 定义的 y 调用对 __getattr__.

的调用