我正在研究Python的对象属性访问模式(Descriptor HowTo Guide和Data model docs)。我无法清楚理解的是,为什么Guido为对象提供__getattr__
和__getattribute__
方法?它们都完全相同,但调用方式不同。
对我而言,似乎设计糟糕的课程可以通过更糟糕的设计来修复。我的意思是,如果某些东西需要重构,它就不应该被粘合了#34;使用高优先级或高优先级调用魔术方法。
问题是 - 如果一个人足够完美,为什么会有两种相似的方法呢?
我没有提到描述符,这些描述符是不同的。
答案 0 :(得分:4)
这两种方法用于不同的目的。
__getattribute__
用于所有属性访问。如果后者无法找到属性,则__getattr__
仅被__getattribute__
称为。
实现正确的__getattr__
方法要比实现__getattribute__
替换方法容易得多。当然,在这种情况下你可以不用__getattr__
,但这也会使实现常见的用例变得更加困难。
例如,在__getattr__
中,您可以轻松访问self
上的其他现有属性;如果您需要self.bar
来实现动态属性,那么这很容易实现。在__getattribute__
中,您无法访问具有正常属性访问权限的self
上的任何内容,因为这些都由__getattribute__
方法处理;如果你尝试过,你最终会进行无限递归。相反,该方法中的所有属性访问必须使用super(ClassName, self).__getattribute__(name)
次调用。
请注意,__getattribute__
始终已实施; object.__getattribute__
提供默认实现。仅在需要拦截默认行为时才使用__getattribute__
;假设您需要在特殊情况下覆盖现有属性,或覆盖正常descriptor behaviour。有关覆盖现有属性访问权限的示例,请参阅Understanding __getattribute__。
将__getattr__
用于其他一切;例如动态属性,其中对象上尚不存在这些属性。比如说,您提供的是一个代理类,其中大多数属性访问都传递给包装对象:
class Proxy(object):
def __init__(self, wrapped):
self._wrapped = wrapped
def foo(self):
return self._wrapped.foo() + 42
def __getattr__(self, name):
return getattr(self._wrapped, name)
此处_wrapped
和foo
直接在Proxy()
上找到,但如果您尝试访问bar
,则Proxy
上不存在该属性我们会调用类__getattr__
,将其转换为self._wrapped
上的属性访问权。