WEB开发网
开发学院软件开发Python Python 2.6.2的字节码指令集一览 阅读

Python 2.6.2的字节码指令集一览

 2010-09-22 11:25:27 来源:WEB开发网   
核心提示: 助记名为“<n>”形式的是未使用的操作码, 既然叫“字节码”,Python 2.6.2的字节码指令集一览(2),这些操作码自然是以字节为单位的咯,于是最多只能表示256个不同的操作码, 对Python字节码的解释方式感兴趣的同学,

助记名为“<n>”形式的是未使用的操作码。

既然叫“字节码”,这些操作码自然是以字节为单位的咯,于是最多只能表示256个不同的操作码。Python实际上只用了百来个操作码。

操作码小于90的为无参数的,指令仅包含操作码自身,共1字节;大于等于90的,则每条指令在操作码之后还带有1个参数,参数长度为2字节,共3字节。

Python程序的字节码在运行时以PyStringObject的形式保存在PyCodeObject的co_code域里。co_code域只含有指令而不包含别的程序数据;变量名、常量等数据均放在别的域里。

Python的字节码指令集是基于栈的指令集。这里说的“栈”不是指函数调用栈,而是指专门用于求值的栈,可以称为“求值栈”(evaluation stack)或者“操作数栈”(operand stack)。求值过程的临时变量都放在求值栈上,指令集中的大部分都是与栈打交道。

例如3 + 4会变成:

Python bytecode代码

LOAD_CONST 0 (3)
LOAT_CONST 1 (4)
BINARY_ADD

假设常量池中下标为0和1的项分别是3和4这两个常量,则头两条指令分别将这两个常量压入求值栈,然后BINARY_ADD指令将求值栈栈顶的两个值弹出,计算加法,并将结果再次压入栈中。理解了这点,则Python的指令集基本上都能顾名思义。操作码对应的具体意义可以在下面的官网文档链接查到。

但既然求值的参数和结果都放在求值栈上,那何必要带参数的指令呢?

关键区别就是,带参数的指令的参数都是一些由编译器指定的常量,例如指向常量池的下标、函数的参数个数、跳转指令的偏移量等。这些值不是Python对象,无法由程序员在源码中显式指定或操纵。

而求值栈上放的则是在源码中显式指定的一些参与计算的值,或者计算后的中间结果。这些值都是Python对象,其行为遵循Python类型系统的规定。

Python字节码中所有控制流指令都是带参数的,并且它们都不额外从求值栈取任何参数。这使得Python字节码程序的控制流在编译时就确定下来,或者说是可静态确定的。这样可以降低控制流被程序代码破坏的风险,也方便了解释器的实现。

python.org上关于Python字节码的详细介绍文档我只找到了一份,是对应Python 2.5.2的字节码列表。Python 2.6.2中大部分指令与这份文档中的相同,但有些细节不同,例如文档中说DUP_TOPX的参数范围是1-5,但在Python 2.6.2里实际上只允许2-3的范围。

在Python 3.x中字节码有了新的调整,至少PRINT_*系列的字节码都取消了。本帖开头的代码在Python 3.x上也可以运行,有兴趣的同学可以对比看看。

对Python字节码的解释方式感兴趣的同学,可以从ceval.c入手,观察Python虚拟机的核心——PyEval_EvalFrameEx()的实现。

上一页  1 2 

Tags:Python 字节 指令

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接