我最近在参与Python字节码相关的工作,想与大家分享一些这方面的经验。更准确的说,我正在参与2.6到2.7版本的CPython解释器字节码的工作。
Python是一门动态语言,在命令行工具下运行时,本质上执行了下面的步骤:
Python解释器是基于栈的。要理解数据流向,我们需要知道每条指令的栈效应(如,操作码和参数)。
探索Python二进制文件
得到一个二进制文件字节码的最简单方式,是对CodeType结构进行解码:
123456 | ; html–script: false ]import marshalfd = open(\’path/to/my.pyc\’, \’rb\’)magic = fd.read(4) # 魔术数,与python版本相关date = fd.read(4) # 编译日期code_object = marshal.load(fd)fd.close() |
code_object包含了一个CodeType对象,它代表被加载文件的整个模块。为了查看这个模块的类定义、方法等的所有嵌套编码对象(编码对象,原文为code object),我们需要递归地检查CodeType的常量池。就像下面的代码:
123456789 | ; html–script: false ]import types def inspect_code_object(co_obj, indent=\’\’):print indent, \”%s(lineno:%d)\” % (co_obj.co_name, co_obj.co_firstlineno)for c in co_obj.co_consts:if isinstance(c, types.CodeType):inspect_code_object(c, indent + \’ \’) inspect_code_object(code_object) # 从第一个对象开始 |
这个案例中,我们打印出一颗编码对象树,每个编码对象是其父对象的子节点。对下面的代码:
1234567 | ; html–script: false ]class A:def __init__(self):passdef __repr__(self):return \’A()\’a = A()print a |
我们得到的树形结果是:
1234 | <module>(lineno:2) A(lineno:2) __init__(lineno:3) __repr__(lineno:5) |
为了测试,我们可以通过compile指令,编译一个包含Python源码的字符串,从而能够得到一个编码对象:
1 | co_obj = compile(python_source_code, \' |
要获取更多关于编码对象的信息,我们可以查阅Python文档的co_* fields 部分。
初见字节码
一旦我们得到了编码对象,我们就可以开始对它进行拆解了(在co_code字段)。从字节码中解析出它的含义:
• 解释操作码的含义
• 提取任意参数
dis模块的disassemble函数展示了是如何做到的。对我们前面例子,它输出的结果是:
1234567891011121314151617 | 2 0 LOAD_CONST 0 (\’A\’) 3 LOAD_CONST 3 (()) 6 LOAD_CONST 1 (<code object A at 0x42424242, file \” 我最近在参与Python字节码相关的工作,想与大家分享一些这方面的经验。更准确的说,我正在参与2.6到2.7版本的CPython解释器字节码的工作。 Python是一门动态语言,在命令行工具下运行时,本质上执行了下面的步骤:
Python解释器是基于栈的。要理解数据流向,我们需要知道每条指令的栈效应(如,操作码和参数)。 探索Python二进制文件 得到一个二进制文件字节码的最简单方式,是对CodeType结构进行解码:
code_object包含了一个CodeType对象,它代表被加载文件的整个模块。为了查看这个模块的类定义、方法等的所有嵌套编码对象(编码对象,原文为code object),我们需要递归地检查CodeType的常量池。就像下面的代码:
这个案例中,我们打印出一颗编码对象树,每个编码对象是其父对象的子节点。对下面的代码:
我们得到的树形结果是:
为了测试,我们可以通过compile指令,编译一个包含Python源码的字符串,从而能够得到一个编码对象:
要获取更多关于编码对象的信息,我们可以查阅Python文档的co_* fields 部分。 初见字节码 一旦我们得到了编码对象,我们就可以开始对它进行拆解了(在co_code字段)。从字节码中解析出它的含义: dis模块的disassemble函数展示了是如何做到的。对我们前面例子,它输出的结果是:
|
下一篇:Python的中文编码问题