为什么反汇编 python class 定义显示两个相同的 LOAD_CONST 与 class 名称?

Why disassembly a python class definition shows two identical LOAD_CONST with the class name?

我想知道为什么在定义 class 时 python 会两次生成具有相同值(class 名称)的 LOAD_CONST。当我 运行 此代码时:

from dis import dis

dis("class A(): pass")

这是我得到的输出:

  1           0 LOAD_BUILD_CLASS
              2 LOAD_CONST               0 (<code object A at 0x0000021DCE681B70, file "<dis>", line 1>)
              4 LOAD_CONST               1 ('A')
              6 MAKE_FUNCTION            0
              8 LOAD_CONST               1 ('A')
             10 CALL_FUNCTION            2
             12 STORE_NAME               0 (A)
             14 LOAD_CONST               2 (None)
             16 RETURN_VALUE

Disassembly of <code object A at 0x0000021DCE681B70, file "<dis>", line 1>:
  1           0 LOAD_NAME                0 (__name__)
              2 STORE_NAME               1 (__module__)
              4 LOAD_CONST               0 ('A')
              6 STORE_NAME               2 (__qualname__)
              8 LOAD_CONST               1 (None)
             10 RETURN_VALUE

正如您在第 3 行和第 5 行中看到的,有两个 LOAD_CONST 名称为 class。

如果 class 名称已经加载,为什么要用相同的数据制作第二个 LOAD_CONST?这与 LOAD_CONST 之间的 MAKE_FUNCTION 有关系吗?

我运行在python 3.7.4 64 位

上安装这个

TL;DR: CPython 中的类型创建暂时使用函数对象作为 class 主体。第一个“A”用作此函数的名称。第二个“A”用于 class 名称。

post的其余部分详细解释了此反汇编:

 0 LOAD_BUILD_CLASS

builtins.__build_class__压入堆栈。它后来被 CALL_FUNCTION 调用以构造一个 class.

 2 LOAD_CONST               0 (<code object A at 0xCAFEF00D, file "<dis>", line 1>)

将代码对象压入堆栈(这实际上包含已解析的 class 块 - 继续阅读)

 4 LOAD_CONST               1 ('A')

将 'A' 压入堆栈

 6 MAKE_FUNCTION            0

将一个新的函数对象压入堆栈。这个动作还消耗了栈上的prev两个东西(这个函数的code obj和它的限定名)

 8 LOAD_CONST               1 ('A')

再次将 'A' 压入堆栈,以便可以用作 builtins.__build_class__ 中的第二个参数,即 class 名称。

10 CALL_FUNCTION            2

消耗 'A' 和堆栈中的一个函数对象,调用 __build_class__(<func>, 'A')。 op 名称后的 2 指的是被咀嚼的位置参数的数量。 Right-most 位置参数位于堆栈顶部,因此它们将是:class 名称 'A',然后是 MAKE_FUNCTION 中剩余的对象,它体现了 class定义。这些参数的“下方”是可调用的 __build_class__,此操作也使用它。提供了 __build_class__(func, name, /, *bases, [metaclass], **kwds) -> class 接受的可选参数中的 None 个。

12 STORE_NAME               0 (A)

A = <top of stack>,本质上是在命名空间

中绑定新创建的class obj
14 LOAD_CONST               2 (None)

RETURN_VALUE 将 return 栈顶,但是 class 语句 exec 不需要 return 值,所以加载 None 之前returning.

16 RETURN_VALUE

我们完成了。

要了解为什么 __build_class__ 将函数作为第一个参数,请参阅 this post from Guido。函数对象用于 class 主体,我猜是为了方便实现。