为什么反汇编 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 主体,我猜是为了方便实现。
我想知道为什么在定义 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>
,本质上是在命名空间
14 LOAD_CONST 2 (None)
RETURN_VALUE 将 return 栈顶,但是 class 语句 exec 不需要 return 值,所以加载 None
之前returning.
16 RETURN_VALUE
我们完成了。
要了解为什么 __build_class__
将函数作为第一个参数,请参阅 this post from Guido。函数对象用于 class 主体,我猜是为了方便实现。