Python 3 __getattribute__ vs点访问行为

时间:2016-08-19 16:35:24

标签: python python-3.x

我读了一下python的对象属性查找(这里:https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/#object-attribute-lookup)。

看起来非常直接,所以我试了一下(python3):

class A:
    def __getattr__(self, attr):
        return (1,2,3)

a = A()

a.foobar #returns (1,2,3) as expected
a.__getattribute__('foobar') # raises AttributeError

我的问题不是两个应该是完全相同的吗?

为什么第二个会引发属性错误?

显然,答案是a.foobar的逻辑与a.__getattribute("foobar")的逻辑不同。根据{{​​3}}:a.foobar调用a.__getattribute("foobar"),如果它引发了AttributeError,则会调用a.-__getattr__('foobar')

所以看来这篇文章在他们的图表中有错误。这是对的吗?

另一个问题:a.foobar的真正逻辑在哪里?我认为它在__getattribute__,但显然不完全。

编辑: 不重复

data model。 我在这里问object.fooobject.__getattribute__("foo")之间有什么不同。这与__getattr__ vs __getatribute__不同,这是微不足道的......

1 个答案:

答案 0 :(得分:5)

很容易得到__getattribute__比实际更负责的印象。 thing.attr未直接翻译为thing.__getattribute__('attr')__getattribute__不对调用__getattr__负责。

__getattr__的回退发生在__getattribute__之外的属性访问机制部分。属性查找过程的工作方式如下:

  • 通过直接搜索对象的类型MRO找到__getattribute__方法,绕过常规属性查找过程。
  • 试试__getattribute__
    • 如果__getattribute__返回了某些内容,则属性查找过程完成,这就是属性值。
    • 如果__getattribute__引发了非AttributeError,则属性查找过程完成,异常传播出查找。
    • 否则,__getattribute__引发了一个AttributeError。查找继续。
  • 以与__getattr__相同的方式查找__getattribute__方法。
    • 如果没有__getattr__,则属性查找过程完成,__getattribute__的AttributeError传播。
  • 尝试__getattr__,然后返回或提高__getattr__返回或加注。

至少,就语言语义而言,它就是这样的。就低级实现而言,其中一些步骤可能会在不必要的情况下进行优化,并且有一些我没有描述过的tp_getattro之类的C钩子。除非你想深入了解CPython解释器源代码,否则你不必担心这种事情。