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

Why are the lookup procedures for getting an attribute from a class and from an instance different?

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

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

它们差别不大,书中的描述涵盖了它们的两个不同之处:

  1. 在 class 实例上找到的描述符(在 class 上找不到)不会被调用(a.x = somedescriptor() 其中 a 是 class 实例,而不是 class,后跟 a.x 将只是 return 你刚刚创建的 somedescriptor() 的实例),而在元 class 上找到的描述符实例即 class(在 metaclass 上找不到之后)被调用 None 作为它被调用的实例(A.x = somedescriptor() 其中 A 是metaclass 实例,而不是 metaclass,将在您刚刚创建的 somedescriptor() 上调用 .__get__(None, A))。这允许像 @classmethod 这样的东西通过将方法绑定到 class 本身来工作,无论它是在 class 的实例还是 class 本身的实例上查找。
  2. Class 实例没有“父实例”的概念(class 实例本身的命名空间是一个扁平的 dict,即使与之关联的属性class 实例由来自多个继承级别的方法定义),因此基于 MRO 的查找的想法是元class 实例所独有的。

其他的都差不多,只是这本书在这里掩盖了元class的概念,因为大多数class都是基[=21=的实例],它没有特殊的行为。如果您有 type 以外的元 class,则在 class 上查找属性时应用完整的实例查找规则(它只是 [=37= 的 class ] 是元class).

他们可能在早期试图避免 metaclasses 的复杂性,但在这个过程中使得实例查找规则似乎不适用于 classes;他们这样做,只是 classes 在基本查找过程中添加了一些额外的规则。