PyCodeObject
python源代码被编译为字节码,同时还有字符串、常量值等一切有用的静态信息都存储在一个运行时对象中pycodeobject,有时(被import、使用py_compile、compiler)会被存储到文件中pyc(这样在下次运行时就不用再编译了)。
typedef struct {
PyObject_HEAD
int co_argcount; // 位置参数的个数 比如函数的位置参数个数
int co_nlocals; // 局部变量的个数 包含位置参数个数
int co_stacksize; // 执行所需的栈空间
int co_flags;
PyObject *co_code; // 这个里面放的就是编译好的指令的字节码 str
PyObject *co_consts; // 保存所有常量 tuple
PyObject *co_names; // 保存所有符号 tuple
PyObject *co_varnames; // 保持所有局部变量名
PyObject *co_freevars; // 用于实现闭包的
PyObject *co_cellvars; // 内部嵌套函数所引用的局部变量名集合
PyObject *co_filename; // 对应的py文件的完整路径
PyObject *co_name; // codeblock的名字,通常是函数名、类名
int co_firstlineno; // 在py文件中的起始行
PyObject *co_lnotab; // 字节码指令和py文件中行号的对应关系
void *co_zombieframe; /* for optimization only (see frameobject.c) */
PyObject *co_weakreflist; /* to support weakrefs to code objects */
} PyCodeObject;
每当python进入一个命名空间或作用域就创建一个对应的codeobject,名字空间一个套一个形成一条名字空间链,python虚拟机在执行中有很大一部分时间在从这条名字空间链中确定一个符号所对应的对象是什么(把全局变量接入局部的优化方式)。
在python中有对应PyCodeObject的对象code:
source = open("demo.py").read()
co = compile(source, 'demo.py', 'exec')
co 这个code对象就有对应PyCodeObject的属性
co_code的读取
通过co直接拿co_code获取的是二进制的代码表示,可以使用dis工具来解析
import dis
dis.dis(co)
pyc文件
python的import机制会触发pyc文件的产生,还可以利用py_compile、compiler等。
import imp
import sys
def generate_pyc(name):
fp, pathname, descripton = imp.find_module(name)
imp.load_module(name, fp, pathname, description)
if fp:
fp.close()
写入
pyc文件包含magic number(Python版本标志)、pyc文件创建时间、codeobject。
写入字符串时:
1、写入普通字符串:类型+长度+值
2、写入intern字符串