如何在不违反默认行为的情况下覆盖Python中的__getattr__?
我想覆盖类的__getattr__
方法来做一些奇特的事情,但我不想打破默认行为。
什么是正确的方法来做到这一点?
重写__getattr__
应该没问题 – 只有当__getattr__
被调用时才是最后的手段,即如果实例中没有与名称匹配的属性。 例如,如果你访问foo.bar
,那么只有当foo
没有名为bar
属性时才会调用__getattr__
。 如果属性是你不想处理的AttributeError
,则引发AttributeError
:
class Foo(object): def __getattr__(self, name): if some_predicate(name): # ... else: # Default behaviour raise AttributeError
但是,与__getattr__
不同, __getattribute__
将首先被调用(仅适用于新的types,即从对象inheritance的types)。 在这种情况下,您可以保留默认行为,如下所示:
class Foo(object): def __getattribute__(self, name): if some_predicate(name): # ... else: # Default behaviour return object.__getattribute__(self, name)
有关更多信息,请参阅Python文档 。
class A(object): def __init__(self): self.a = 42 def __getattr__(self, attr): if attr in ["b", "c"]: return 42 raise AttributeError("%r object has no attribute %r" % (self.__class__, attr)) # exception text copied from Python2.6
>>> a = A() >>> aa 42 >>> ab 42 >>> a.missing Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in __getattr__ AttributeError: 'A' object has no attribute 'missing' >>> hasattr(a, "b") True >>> hasattr(a, "missing") False
为了扩展Michael答案,如果你想使用__getattr__
保持默认行为,你可以这样做:
class Foo(object): def __getattr__(self, name): if name == 'something': return 42 # Default behaviour return self.__getattribute__(name)
现在exception信息更具描述性:
>>> foo.something 42 >>> foo.error Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 5, in __getattr__ AttributeError: 'Foo' object has no attribute 'error'