Python 为什么从类和实例获取属性的查找过程不同?
简而言之,Python描述了获取属性时的查找过程。这本书区分了两种情况Python 为什么从类和实例获取属性的查找过程不同?,python,python-3.x,class,attributes,metaclass,Python,Python 3.x,Class,Attributes,Metaclass,简而言之,Python描述了获取属性时的查找过程。这本书区分了两种情况 从类中获取属性时的查找过程,例如cls.name 从类中获取属性 使用语法C.name引用属性时 在类对象C上,查找分两步进行: 当name是C.\uuuu dict\uuuu中的一个键时,C.name从C.\uu dict\uuuu['name']中获取值v。然后,当v为 描述符(即,type(v)提供一个名为 \uuuu get\uuuu),C.name的值是调用 键入(v)。\uu获取(v,无,C)。当v不是描述符时
- 从类中获取属性时的查找过程,例如
从类中获取属性 使用语法cls.name
引用属性时 在类对象C.name
上,查找分两步进行:C
- 当
是name
中的一个键时,C.\uuuu dict\uuuu
从C.name
中获取值C.\uu dict\uuuu['name']
。然后,当v
为 描述符(即,v
提供一个名为type(v)
),C.name的值是调用\uuuu get\uuuu
。当键入(v)。\uu获取(v,无,C)
不是描述符时,v
C.name的值为v
- 当
不是name
C.中的键时,
将查找委托给C.name
的基类,这意味着它在C
上循环 祖先类并尝试在每个(in)方法上进行名称查找 决议顺序,如第页“方法决议顺序”所述 113)C
类型
类),根据这本书,为什么从类中获取属性的查找过程和从实例中获取属性的查找过程不同呢?它们没有太大的不同,书中的描述涵盖了两种不同的方式:
a.x=somedescriptor()
其中a
是类实例,而不是类,后跟a.x
将只返回您刚刚创建的somedescriptor()
的实例),虽然在元类实例上找到的描述符,即类(在元类上找不到之后)被调用时,其实例是None
(a.x=somedescriptor()
,其中a
是元类实例,而不是元类,将调用上的。\u get\uuuuu(None,a)
您刚刚制作了一个)。这允许像@classmethod
这样的东西通过将方法绑定到类本身来工作,不管它是在类的实例上查找还是在类本身上查找dict
,即使与该类实例相关联的属性是由来自多个继承级别的方法定义的),因此基于MRO的查找思想对于元类实例来说是独特的类型
的实例,它没有特殊的行为。如果您的元类不是类型
,则在查找类的属性时会应用完整的实例查找规则(只是类的类是元类)
他们可能在早期试图避免元类的复杂性,但在这个过程中,实例查找规则似乎不适用于类;确实如此,只是类在基本查找过程中添加了一些额外的规则。谢谢!你是说从书中的类中获取属性的查找过程只有在类是
类型
类的实例时才起作用吗?我还可以问一下你的想法吗?@Tim:这意味着当它是类型
的实例时,规则会像写的那样适用,但是如果它有其他元类,这些规则可以调用“普通”实例的所有行为。一个真正简单的元类可能最终表现出与类型
相同的行为(因为它是类型
的一个子类,它不需要有任何不同),一个更复杂的元类可能会定义所有使实例更复杂的小奇怪的事情。所谓“它是类型
的一个子类”,你的意思是“它是类型
的一个实例”吗相反(我猜“it”的意思是“一个非常简单的元类”)?如果一个真正简单的元类与类型
没有任何区别,那么使用真正简单的元类而不是直接使用类型
作为元类的原因是什么?@Maggyero:啊,你说得对。我花了一点时间弄明白你在说什么(我最初把它误读为一个声明,声称在访问使用它的类上的内容时,元类上没有调用描述符协议)。您不能让常规实例在每个实例属性上调用描述符协议(比如a.x=property(somefunc)
不会让a.x
执行任何操作,而是返回原始的属性
对象),但当元类不通过描述符提供重写时,它会在每个类属性上发生。我将调整答案以涵盖这一点。