В классе старого стиля, __getattr__
используется для большего разнообразия доступа к атрибутам, включая магические методы.Оператор %
пытается вызвать t.__repr__()
, чтобы заполнить заполнитель %r
, но t.__repr__
оценивается как t.__getattr__('__repr__')
, что возвращает 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
Используйте класс нового стиля, __getattr__
вызывается только в том случае, если атрибут не может быть найден с помощью обычного метода (проверка__dict__
атрибут экземпляра или любого из классов в 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 экземпляра, поэтому его значение возвращается напрямую.Только y
, который не определен как f
, Foo
или object
, вызывает вызов __getattr__
.