Python 编译

来源:互联网 发布:2017java 笔试题 编辑:程序博客网 时间:2024/06/18 16:40
Python 实现了栈式虚拟机 (Stack-Based VM) 架构,通过与机器⽆无关的字节码来实现跨平台执⾏行
能⼒力。这种字节码指令集没有寄存器,完全以栈 (抽象层⾯面) 进⾏行指令运算。尽管很简单,但对普通
开发⼈人员⽽而⾔言,是⽆无需关⼼心的细节。
要运⾏行 Python 语⾔言编写的程序,必须将源码编译成字节码。通常情况下,编译器会将源码转换成
字节码后保存在 pyc ⽂文件中。还可⽤用 -O 参数⽣生成 pyo 格式,这是简单优化后的 pyc ⽂文件。
编译发⽣生在模块载⼊入那⼀一刻。具体来看,⼜又分为 pyc 和 py 两种情况。
载⼊入 pyc 流程:
• 核对⽂文件 Magic 标记。
• 检查时间戳和源码⽂文件修改时间是否相同,以确定是否需要重新编译。
• 载⼊入模块。
如果没有 pyc,那么就需要先完成编译:
• 对源码进⾏行 AST 分析。
• 将分析结果编译成 PyCodeObject。
• 将 Magic、源码⽂文件修改时间、PyCodeObject 保存到 pyc ⽂文件中。
• 载⼊入模块。
20
Magic 是⼀一个特殊的数字,由 Python 版本号计算得来,作为 pyc ⽂文件和 Python 版本检查标记。
PyCodeObject 则包含了代码对象的完整信息。
typedef struct {
PyObject_HEAD
int co_argcount;? ? // 参数个数,不包括 *args, **kwargs。
int co_nlocals;? ? ? // 局部变量数量。
int co_stacksize;? ? // 执⾏行所需的栈空间。
int co_flags;? ? ? // 编译标志,在创建 Frame 时⽤用得着。
PyObject *co_code;? ? // 字节码指令。
PyObject *co_consts;? ? // 常量列表。
PyObject *co_names;? ? // 符号列表。
PyObject *co_varnames;? ? // 局部变量名列表。
PyObject *co_freevars;? ? // 闭包: 引⽤用外部函数名字列表。
PyObject *co_cellvars;? ? // 闭包: 被内部函数引⽤用的名字列表。
PyObject *co_filename;? ? // 源码⽂文件名。
PyObject *co_name;? ? // PyCodeObject 的名字,函数名、类名什么的。
int co_firstlineno;? ? // 这个 PyCodeObject 在源码⽂文件中的起始位置,也就是⾏行号。
PyObject *co_lnotab;? ? // 字节码指令偏移量和源码⾏行号的对应关系,反汇编时⽤用得着。
void *co_zombieframe; ? // 为优化准备的特殊 Frame 对象。
PyObject *co_weakreflist;? // 为弱引⽤用准备的...
} PyCodeObject;
⽆无论是模块还是其内部的函数,都被编译成 PyCodeObject 对象。内部成员都嵌套到 co_consts
列表中。
>>> pycat test.py
"""
Hello, World!
"""
def add(a, b):
return a + b
c = add(10, 20)
>>> code = compile(open("test.py").read(), "test.py", "exec")
>>> code.co_filename, code.co_name, code.co_names
('test.py', '<module>', ('__doc__', 'add', 'c'))
>>> code.co_consts
('\n Hello, World!\n', <code object add at 0x105b76e30, file "test.py", line 5>, 10,
20, None)
>>> add = code.co_consts[1]
>>> add.co_varnames
('a', 'b')
21
除了内置 compile 函数,标准库⾥里还有 py_compile、compileall 可供选择。
>>> import py_compile, compileall
>>> py_compile.compile("test.py", "test.pyo")
>>> ls
main.py*? test.py? ? test.pyo
>>> compileall.compile_dir(".", 0)
Listing . ...
Compiling ./main.py ...
Compiling ./test.py ...
如果对 pyc ⽂文件格式有兴趣,但⼜又不想看 C 代码,可以到 /usr/lib/python2.7/compiler ⺫⽬目录⾥里
寻宝。⼜又或者你对反汇编、代码混淆、代码注⼊入等话题更有兴趣,不妨看看标准库⾥里的 dis。
0 0
原创粉丝点击