有人可以从 python 字节码中解释 CALL_FUNCTION 和 RETURN_VALUE

Can someone explain CALL_FUNCTION and RETURN_VALUE from python bytecode

我正在尝试理解 python 字节码,但我被 CALL_FUNCTION 和 RETURN_VALUE 所吸引。

函数有自己的堆栈吗?如果不是,文档中“Returns 给函数调用者的 TOS”是什么意思?

抱歉含糊不清

在 CPython 中,每个函数都有自己的堆栈,它在 CPython 中称为帧,它是 implementation-specific 细节(非常古老的)和 [= 的其他实现69=] 像 IronPython1 和 Jython 没有这个功能或以不同的方式实现它。

澄清当我们说堆栈时涉及多个堆栈:

  1. Python stack: 帧objects
  2. 的栈
  3. 函数取值栈:将每一帧object中的值存入此栈,在本帧范围内进行操作2
  4. C 堆栈:用于 C 函数调用

当一个函数被调用时,首先创建一个新框架 object 并放置在 Python stack 上。这个框架 object 包含函数的代码 object,函数可以访问的全局变量,函数中定义的局部变量也存储在框架 object.[=30 中=]

您可以使用检查模块中提供的实用程序在 Python stack and current frame 中获取当前帧。

这个问题是它是一个 Python object,它有自己的类型 PyFrame_Type, it gets reference count(gets all headers from PyVarObject) 并且会消耗一些内存,如果我们有一个函数调用链,每次我们都会在整个堆内存中创建这些帧object。

在 Python 3.11 中,框架 object 将被一个没有 object header 的结构数组替换。框架 object 仍然可用,但 only if we request for it 使用 inspect.currentframe()sys._get_frame()


2 函数值堆栈

我们可以通过访问函数代码 co_stacksize 属性来检查函数的堆栈大小 object,这个值是在编译期间确定的:

>>> def func():
...     a = 1
...     b = 2
...     c = 3
...     d = a + b + c
...
>>> func.__code__.co_stacksize
2

这里的值为 2 因为要对 a + b + c 求和,它首先将 ab 加载到堆栈 (LOAD_FAST) and performs the sum(BINARY_ADD) 并将结果放回顶部堆栈,现在 c 已加载,并且它与 ab 的总和结果相加。因此,此函数特定的堆栈需要最大大小为 2。


1: flag X:Frames 可以在 IronPython 中使用来启用 CPython like frame objects.