一、背景
python先把代码(也就是.py文件)编译成字节码(对应codeobject对象),然后将字节码提交给python虚拟机,虚拟机按照顺序执行字节码指令完成了程序的执行。本文关注的对象就是codeobject对象。在磁盘上codeobject对象的表现形式就是.pyc文件。
二、编译成字节码
python中有一个内置函数compile(),可以将源文件编译成codeobject,首先看这个函数的说明:
compile(...)
compile(source, filename, mode[, flags[, dont_inherit]]) -> code object
参数1:源文件的内容字符串
参数2:源文件名称
参数3:exec-编译module,single-编译一个声明,eval-编译一个表达式
一般使用前三个参数就够了
使用示例:
#src_file.py
#some function
def f(d=0):
c=1
print "hello"
a=9
b=8
f()
#命令行模式中打开源文件进行编译
>>a=open('src_file.py','r').read()
>>co=compile(a,'src_file','exec')
>>type(co)
#编译出了codeobject对象
>>
三、codeobject对象的属性
codeobject有哪些变量,接上节的内容分析一下
#所有的符号名称
>>> print co.co_names
('f', 'a', 'b')
#模块名、函数名、类名
>>>print co.co_name
#常量集合、函数f和两个int常量a,b,d
>>print co.co_consts
(0, , 9, 8, None)
#可以看到f函数也是一个codeobject,打印f中的局部变量
>>print co.co_consts[1].co_varnames
('c',)
#字节码指令
>>print co.co_code
dZdZdZedS
#代码块在文件中的起始行号
>>print co.co_consts[1].co_firstlineno
2
#代码栈大小
>>print co.co_stacksize
2
#文件名
>>> print co.co_filename
src_file
codeobject的co_code代表了字节码,这个字节码有什么含义?我们可以使用dis模块进行python的反编译:
import dis
dis.dis(co)
>>output
2 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 ()
6 MAKE_FUNCTION 1
9 STORE_NAME 0 (f)
5 12 LOAD_CONST 2 (9)
15 STORE_NAME 1 (a)
6 18 LOAD_CONST 3 (8)
21 STORE_NAME 2 (b)
7 24 LOAD_NAME 0 (f)
27 CALL_FUNCTION 0
30 POP_TOP
31 LOAD_CONST 4 (None)
34 RETURN_VALUE
从反编译的结果来看,python字节码其实是模仿的x86的汇编,将代码编译成一条一条的指令交给一个虚拟的cpu去执行。
第一列:行号
第二列:指令在代码块中的偏移量
第三列:指令
第四列:操作数
第五列:操作数说明
具体在执行字节码的时候,python需要创建栈,又是一个比较重要的对象PyFrameObject。以后再研究。