我阅读了一些关于 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") 的逻辑不同。根据data model : a.foobar 调用 a.__getattribute("foobar") 如果它引发 AttributeError,它调用 a.-__getattr__('foobar')
看来这篇文章的图表有误。这是正确的吗?
还有一个问题:a.foobar 的真正逻辑在哪里?我认为它在 __getattribute__ 中,但显然不完全是。
编辑: 不是的重复
Difference between __getattr__ vs __getattribute__ . 我在这里问 object.foo 和 object.__getattribute__("foo") 有什么区别。这与 __getattr__ 和 __getatribute__ 不同,后者很简单......
请您参考如下方法:
很容易产生这样的印象,即 __getattribute__ 比实际负责的更多。 thing.attr 不会直接转换为 thing.__getattribute__('attr'),并且 __getattribute__ 不负责调用 __getattr__ 。
回退到 __getattr__ 发生在位于 __getattribute__ 之外的属性访问机制部分。属性查找过程是这样的:
- 通过直接搜索对象类型的 MRO 找到
__getattribute__方法,绕过常规属性查找过程。 - 试试
__getattribute__。- 如果
__getattribute__返回了一些东西,属性查找过程就完成了,那就是属性值。 - 如果
__getattribute__引发非 AttributeError,则属性查找过程完成,并且异常传播到查找之外。 - 否则,
__getattribute__会引发 AttributeError。查找继续。
- 如果
- 以与查找
__getattribute__相同的方式查找__getattr__方法。- 如果没有
__getattr__,则属性查找过程完成,并且传播来自__getattribute__的AttributeError。
- 如果没有
- 尝试
__getattr__,并返回或提高任何__getattr__返回或提高的值。
至少,就语言语义而言,它是这样工作的。在低级实现方面,其中一些步骤在不需要的情况下可能会被优化掉,还有像 tp_getattro 这样的 C 钩子(Hook)我没有描述。除非您想深入研究 CPython 解释器源代码,否则您无需担心此类事情。
