如何在不违反默认行为的情况下覆盖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'