python属性查找过程如何工作?

时间:2012-06-26 15:54:38

标签: python attributes python-datamodel

当我说" python属性查找过程"我的意思是:当你写x.foo时,python会做什么?

在网上搜索我没有找到关于此的大量文档,我找到的最好的论文之一恢复了以下步骤的过程(你可以看到完整的文章here

  1. 如果attrname是objectname的特殊(即Python提供的)属性,则返回它。
  2. 检查objectname .__ class __.__ dict__是否为attrname。如果它存在且是数据描述符,则返回描述符结果。在同一案例中搜索objectname .__ class__的所有基础。
  3. 检查attrname的objectname .__ dict__,如果找到则返回。如果objectname是一个类,也搜索它的基础。如果它是一个类,并且它或其基础中存在描述符,则返回描述符结果。
  4. 检查objectname .__ class __.__ dict__是否为attrname。如果它存在且是非数据描述符,则返回描述符结果。如果它存在,并且不是描述符,则返回它。如果它存在并且是数据描述符,我们不应该在这里,因为我们将在第2点返回。搜索objectname .__ class__的所有基础以查找相同的情况。
  5. 提升属性错误。
  6. 首先这看似正确,但属性查找过程有点复杂,例如对于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__对于&lt;的实例是不同的。键入&#39; type&#39; &GT;和&lt;类型&#39;对象&#39;取代。对于C.foo(),&#39; foo&#39;首先在C .__ dict__上搜索,如果找到则返回(而不是搜索类型(C))和x.foo()&#39; foo&#39;在类型(x).__ dict__和x .__ dict __。
    • 上搜索
    • __ getattribute__方法总是在类型(x)上解析,我在这里不了解的是最后一种情况:c .__ getattribute__,isn&#t; t object包含一个方法__getattribute __(和C继承自object),那么为什么要调用元类getattribute方法呢?

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

1 个答案:

答案 0 :(得分:4)

如果您添加print("Metaclass getattribute invoked:", self, name),则会看到:

>>> 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__以构建表达式repr的{​​{1}},以便它可以打印c.__getattribute__的{​​{1}}。

btw,C对类和元类的工作方式相同;首先在实例上查找属性,然后在实例的类型上查找。

__name__