python - 调用python库函数的过程

标签 python bytecode

我试图理解调用 python 函数的过程,我创建了简单的 .pyc 文件来调用 os.listdir('.'), 我看到 oslistdir 保存在 co_names 表中,当执行 CALL_FUNCTION 字节码指令时,如何 os 库正在被识别?它是使用 co_names 表的名称吗? python 是否开始搜索名为 os.pyc 的模块?如果是这样,python 如何知道 .pyc 模块中调用的函数的字节码偏移量在哪里?

谢谢。

dis 模块字节码片段

  5          28 LOAD_NAME                0 (os)
             31 LOAD_ATTR                2 (listdir)
             34 LOAD_CONST               3 ('.')
             37 CALL_FUNCTION            1

最佳答案

Python 的虚拟机是基于堆栈的。对 Python 对象的引用被压入堆栈,操作码将其中一个或多个拉出,执行一些操作,并且通常将结果推回堆栈以供下一个操作码使用。

顺便说一句,您可能会发现反汇编一个简单的算术计算很有趣(必须完全重新排序运算才能以这种格式工作)。或者继续阅读 FORTH; Python 的 VM 与 FORTH 的并无不同,但实际的 FORTH 语言 以 Python 所没有的方式反射(reflect)了它的 VM。无论如何,继续解释......

LOAD_NAME 操作码获取对 os 对象的引用。 (它恰好是一个模块,但不管它是什么类型的对象,它对所有类型的对象都是一样的。)引用放在堆栈的顶部。

(这不会搜索或加载模块。Python 已经使用先前的 import 语句导入了对 os 的引用,并且只是从中检索此引用全局变量。)

LOAD_ATTR 操作码获取对堆栈顶部引用的任何对象的 listdir 对象的引用。 (同样,此引用是一个函数,但这并不重要。)堆栈顶部的对象引用被弹出,LOAD_ATTR 的结果被压入。

LOAD_CONST 操作码获取对字符串 '.' 的引用并将其压入堆栈顶部。

现在 CALL_FUNCTION 从堆栈中弹出 1 个引用。这是对字符串 '.' 的引用,os.listdir 的参数。 (它知道弹出 1 个引用,因为 CALL_FUNCTION 的操作数是 1。如果函数接受更多参数,就会有更多的 LOAD 操作码和 的操作数CALL_FUNCTION 操作码会更高。)它从堆栈中弹出另一个引用,这是对 os.listdir 函数的引用。然后它使用参数调用函数。然后将函数的返回值压入堆栈,供其他操作码使用。

正如您所发现的,名称 oslistdir 存储在表 co_names 中。 LOAD_NAMELOAD_ATTR 操作码的操作数是该表的索引。 '.' 的处理方式类似,只是它存储在 co_consts 表中。

关于python - 调用python库函数的过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35469722/

相关文章:

python - 如何生成名称中包含今天日期的文件?

python - Heroku:将文件放入 bin 文件夹

python - 使用 Python 将 Google Sheet 下载为 CSV,生成只有一行的 CSV

java - 如何调试在类加载时注入(inject) VM 的字节码?

java - 有什么方法可以从字节码重新生成堆栈图?

python - 在 C python 中,访问字节码评估堆栈

java - 无法使用 zipfile.ZIP_DEFLATED 压缩方法提取使用 Python 创建的 ZIP 文件

python - 使用 mysql 数据库配置 apache 超集

java - 获取没有堆栈跟踪的 "ArrayIndexOutOfBoundsException: null"

java - 从命令行启动文件的.class命令