How python attribute lookup process works?
当我说"python属性查找过程"时,我的意思是:编写x.foo时,python会做什么??
在网上搜索我没有找到很多关于这方面的文档,我找到的最好的一篇论文继续进行以下步骤(您可以在这里看到完整的文章)
起初,这看起来似乎是正确的,但是属性查找过程有点复杂,例如对于x.foo,如果x是一个类或实例,它的行为就不一样。
我找到了一些不能用这种方法解释的样品。考虑下面的python代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Meta(type): def __getattribute__(self, name): print("Metaclass getattribute invoked:", self) return type.__getattribute__(self, name) def __getattr__(self, item): print('Metaclass getattr invoked: ', item) return None class C(object, metaclass=Meta): def __getattribute__(self, name): print("Class getattribute invoked:", args) return object.__getattribute__(self, name) c=C() |
现在用相应的输出检查以下行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | >> C.__new__ Metaclass getattribute invoked: <class '__main__.C'> <built-in method __new__ of type object at 0x1E1B80B0> >> C.__getattribute__ Metaclass getattribute invoked: <class '__main__.C'> <function __getattribute__ at 0x01457F18> >> C.xyz Metaclass getattribute invoked: <class '__main__.C'> Metaclass getattr invoked: xyz None >> c.__new__ Class getattribute invoked: (<__main__.C object at 0x013E7550>, '__new__') <built-in method __new__ of type object at 0x1E1B80B0> >> c.__getattribute__ Class getattribute invoked: (<__main__.C object at 0x01438DB0>, '__getattribute__') Metaclass getattribute invoked: <class '__main__.C'> <bound method C.__getattribute__ of <__main__.C object at 0x01438DB0>> >> |
我得出的结论是(考虑到我们正在搜索x.foo):
- _对于
和 的实例,getattribute_uuu是不同的。对于c.foo(),首先在c."uu dict"上搜索"foo",如果找到则返回"foo"(而不是搜索类型(c)),对于x.foo(),在类型(x)上搜索"foo"。在"uu dict"和"x"上搜索"foo"。 - _ getattribute_uuu方法总是在类型(x)上解析,我不理解的是最后一种情况:c."getattribute"不是对象包含方法"getattribute"(和c从对象继承),所以为什么要调用元类getattribute方法。
有人能解释一下吗?或者至少告诉我在哪里可以找到关于这个的文档,谢谢。
如果添加
1 2 3 4 | >>> c.__getattribute__ Class getattribute invoked: <__main__.C object at 0x2acdbb1430d0> __getattribute__ Metaclass getattribute invoked: <class '__main__.C'> __name__ <bound method C.__getattribute__ of <__main__.C object at 0x2acdbb1430d0>> |
调用元类
顺便说一句,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> Meta.foo = 1 >>> C.foo ('Metaclass getattribute invoked:', <class '__main__.C'>, 'foo') 1 >>> c.foo ('Class getattribute invoked:', <__main__.C object at 0x2acdbb1430d0>, 'foo') Traceback (most recent call last): File"<stdin>", line 1, in <module> File"<stdin>", line 5, in __getattribute__ AttributeError: 'C' object has no attribute 'foo' >>> C.bar = 2 >>> c.bar ('Class getattribute invoked:', <__main__.C object at 0x2acdbb1430d0>, 'bar') 2 |