为什么在Python中有两种魔术方法来访问对象属性?

时间:2014-07-10 16:07:47

标签: python object attributes accessor

我正在研究Python的对象属性访问模式(Descriptor HowTo GuideData model docs)。我无法清楚理解的是,为什么Guido为对象提供__getattr____getattribute__方法?它们都完全相同,但调用方式不同。

对我而言,似乎设计糟糕的课程可以通过更糟糕的设计来修复。我的意思是,如果某些东西需要重构,它就不应该被粘合了#34;使用高优先级或高优先级调用魔术方法。

问题是 - 如果一个人足够完美,为什么会有两种相似的方法呢?

我没有提到描述符,这些描述符是不同的。

1 个答案:

答案 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)

此处_wrappedfoo直接在Proxy()上找到,但如果您尝试访问bar,则Proxy上不存在该属性我们会调用类__getattr__,将其转换为self._wrapped上的属性访问权。