2012-06-26 130 views
24

当我说“python属性查找过程”我的意思是:当你写x.foo时,python会做什么?python属性查找过程如何工作?

搜索网页,我没有发现有关此多文档,我找到了最好的论文之一恢复了proccess以下步骤(你可以看到完整的文章here

  1. 如果attrname是一个特殊的(即Python提供的)objectname属性,返回它。
  2. 检查对象名.__类__.__ dict__ for attrname。如果它存在并且是数据描述符,则返回描述符结果。搜索objectname .__ class__的所有基地以查找同一个案例。
  3. 检查对象名.__ dict__ for attrname,如果找到则返回。如果objectname是一个类,也搜索其基地。如果它是一个类,并且描述符存在于它或它的基中,则返回描述符结果。
  4. 检查对象名.__类__.__ dict__ for attrname。如果它存在并且是非数据描述符,则返回描述符结果。如果它存在,并且不是描述符,只需返回它。如果它存在并且是一个数据描述符,那么我们不应该在这里,因为我们会在第2点返回。搜索objectname .__ class__的所有基地以查找同一个案例。
  5. 引发AttributeError。

起初这可能看起来不错,但属性查找过程稍微复杂一点,例如对于x.foo,如果x是类或实例,则它的行为不同。

我发现一些样本无法用这种方式解释。请看下面的Python代码:

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() 

现在检查以下线与对应的输出:

>> 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__与<类型'type'>和<类型'object'>的实例不同。对于C.foo(),首先在C .__ dict__上搜索'foo',如果找到则返回(而不是搜索类型(C))并为x.foo()搜索'foo'类型(x).__ dict__和在x .__ dict__上。
  • __getattribute__方法总是在类型(x)上解析,这里我不明白的是最后一种情况:c .__ getattribute__,不是对象包含方法__getattribute__(并且C从对象继承),那么为什么元类getattribute方法被调用。

有人可以解释这个吗?或者至少告诉我哪里可以找到关于此的一些文档,谢谢。

回答

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>> 

元类__getattribute__是越来越调用,以建立表达c.__getattribute__repr,以便它可以打印C__name__

btw,__getattribute__对类和元类的作用相同;该属性首先在实例上查找,然后在实例的类型上查找。

>>> 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 
+2

Python类型和对象http://www.cafepy.com/article/python_types_and_objects/ – amirouche