【发布时间】:2015-11-11 02:46:14
【问题描述】:
我试图通过跟踪不同的字节码/操作码来加深我对 CPython 解释器的理解,因为它们通过 ceval.c 中的解释器循环,用于一个简单的 Python 程序。我使用bytecode 和opcode 表示相同的意思。
我的python程序是这样的:
#filename: test.py
x = 2
y = 3
if x < y:
z = x
elif True:
z = y
else:
z = 100
我正在使用 Python 2.7.8 并使用如下调试标志构建它:
wget https://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz # download
tar xvf Python-2.7.8.tgz # extract
cd Python2.7.8
./configure --with-pydebug # build with debug flag
make -j # parallel make
我有兴趣在解释器循环 ceval.c 中跟踪 switch 语句周围的 for(;;) 循环,从第 964 行开始。
我在 for 循环开始后添加了这些行,以检查解释器是否正在运行我的文件,如果是,则打印出 opcode。
964 for (;;) {
965 if (strcmp(filename, "../test.py") == 0) {
966 printf("%d\n", opcode);
967 }
我得到的输出是(手动添加 cmets 以显示来自 opcode.h 的 opcode DEFINE):
$ ./python.exe ../test.py | cat -n
1 0 // STOP_CODE
2 90 // HAVE_ARGUMENT
3 90 // HAVE_ARGUMENT
4 101 // LOAD_NAME
5 101 // LOAD_NAME
6 101 // LOAD_NAME
7 90 // STORE_NAME
我期望 12 个不同的操作码而不是 7 个,因为当我得到同一个文件的字节码反汇编时,有 12 个字节码命令。
$ ./python.exe -m dis ../pytests/test.py | sed "/^$/d" | cat -n
1 1 0 LOAD_CONST 0 (2)
2 3 STORE_NAME 0 (x)
3 2 6 LOAD_CONST 1 (3)
4 9 STORE_NAME 1 (y)
5 4 12 LOAD_NAME 0 (x)
6 15 LOAD_NAME 1 (y)
7 18 COMPARE_OP 0 (<)
8 21 POP_JUMP_IF_FALSE 33
9 5 24 LOAD_NAME 0 (x)
10 27 STORE_NAME 2 (z)
11 30 JUMP_FORWARD 21 (to 54)
12 6 >> 33 LOAD_NAME
我对 CPython 解释器如何工作的心智模型和/或我记录不同操作码的方法不正确,或两者兼而有之。你能解释一下为什么我从ceval.c 文件的输出和使用python -m dis 包看到不同的操作码吗?
【问题讨论】:
-
当您的意思是“CPython”(“标准" Python 解释器)。就目前而言,这个问题没有太大意义......
-
但是忽略您看到的字节码不同的事实,我认为您希望得到不同数量的字节码:ceval 中的循环只会显示执行的内容(而不是“it/else”的部分跳过)而 dis 会给你一切。