为什么从类和实例中获取属性的查找过程不同?

时间:2023-04-16
本文介绍了为什么从类和实例中获取属性的查找过程不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

Python in a Nutshell 描述了获取属性时的查找过程.本书区分了两种情况

Python in a Nutshell describes the lookup procedures when getting an attribute. The book distinguishes two cases

  • 从类中获取属性时的查找过程,例如cls.name

从类中获取属性

当您使用语法 C.name 来引用属性时在类对象 C 上,查找分两步进行:

When you use the syntax C.name to refer to an attribute on a class object C, the lookup proceeds in two steps:

  1. nameC.__dict__ 中的键时,C.name 获取值 v 来自 C.__dict__['name'] .那么,当 v 是一个描述符(即 type(v) 提供一个名为__get__ ),C.name 的值是调用的结果type(v).__get__(v, None, C) .当 v 不是描述符时,C.name 的值为 v .

  1. When name is a key in C.__dict__, C.name fetches the value v from C.__dict__['name'] . Then, when v is a descriptor (i.e., type(v) supplies a method named __get__ ), the value of C.name is the result of calling type(v).__get__(v, None, C) . When v is not a descriptor, the value of C.name is v .

name 不是 C.__dict__ 中的键时,C.name 将查找委托给 C 的基类,这意味着它在 C 上循环祖先类并尝试对每个类进行名称查找(在方法中解决顺序,如页面上的方法解决顺序"中所述113).

When name is not a key in C.__dict__ , C.name delegates the lookup to C ’s base classes, meaning it loops on C ’s ancestor classes and tries the name lookup on each (in method resolution order, as covered in "Method resolution order" on page 113).

  • 从实例获取属性时的查找过程,例如obj.name

    由于在 Python 3 中,每个类对象实际上都是其元类的一个实例(例如 type 类),根据本书,为什么从类中获取属性的查找过程和从不同实例中获取属性的查找过程?

    Since in Python 3, every class object is actually an instance of its metaclass (e.g. type class), according to the book, why are the lookup procedure for getting an attribute from a class and the lookup procedure for getting an attribute from an instance different?

    推荐答案

    它们并没有非常不同,书中的描述涵盖了它们不同的两种方式:

    They're not very different, and the description from the book covers the two ways in which they differ:

    1. 在类实例上找到的描述符(在类上找不到之后)不会被调用(ax = somedescriptor() 其中 a 是一个类实例,不是一个类,后跟 ax 只会返回你刚刚创建的 somedescriptor() 的实例),而在元类实例上找到的描述符,即一个类(在没有找到之后在元类上)以 None 作为它被调用的实例调用(Ax = somedescriptor() 其中 A 是元类实例,而不是一个元类,将在您刚刚创建的 somedescriptor() 上调用 .__get__(None, A) ).这允许像 @classmethod 这样的东西通过将方法绑定到类本身来工作,无论它是在类的实例上还是在类本身上查找.
    2. 类实例没有父实例"的概念.(类实例本身的命名空间是一个扁平的dict,即使与该类实例关联的属性是由多个继承级别的方法定义的),因此基于MRO的查找的想法是独一无二的到元类实例.
    1. Descriptors found on a class instance (after not being found on the class) don't get invoked (a.x = somedescriptor() where a is a class instance, not a class, followed by a.x will just return the instance of somedescriptor() you just made), while descriptors found on a metaclass instance i.e. a class (after not being found on the metaclass) get invoked with None as the instance it was called on (A.x = somedescriptor() where A is a metaclass instance, not a metaclass, will invoke .__get__(None, A) on the somedescriptor() you just made). This allows stuff like @classmethod to work by binding the method to the class itself whether it's looked up on an instance of the class or the class itself.
    2. Class instances don't have a concept of "parent instances" (the namespace of the class instance itself is a flat dict, even if the attributes associated with that class instance were defined by methods from multiple levels of inheritance), so the idea of MRO-based lookup is unique to metaclass instances.

    其他一切都差不多,只是本书在这里掩盖了元类的概念,因为大多数类都是基本 type 的实例,没有特殊行为.如果您有 type 以外的元类,则在查找类的属性时会应用完整的实例查找规则(只是该类的类是元类).

    Everything else is pretty much the same, it's just that the book is glossing over the concept of metaclasses here, since most classes are instances of the base type, which has no special behaviors. If you have a metaclass other than type, the full instance lookup rules apply when looking up attributes on a class (it's just the class of the class is the metaclass).

    他们可能在早期试图避免元类的复杂性,但在这个过程中,实例查找的规则似乎不适用于类;确实如此,只是类在基本查找过程中添加了一些额外的规则.

    They were probably trying to avoid the complexity of metaclasses early on, but in the process made it seem like the rules for instance lookup didn't apply to classes; they do, it's just that classes add a couple extra rules to the basic lookup procedure.

    这篇关于为什么从类和实例中获取属性的查找过程不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

  • 上一篇:Python 类属性及其初始化 下一篇:如何在 python 中覆盖类属性访问?

    相关文章