千家信息网

Python编译结果之如何理解code对象与pyc文件

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,本篇内容介绍了"Python编译结果之如何理解code对象与pyc文件"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读
千家信息网最后更新 2026年10月31日Python编译结果之如何理解code对象与pyc文件

本篇内容介绍了"Python编译结果之如何理解code对象与pyc文件"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1、Python程序执行过程

与java类似,Python将.py编译为字节码,然后通过虚拟机执行。编译过程与虚拟机执行过程均在python25.dll中。Python虚拟机比java更抽象,离底层更远。

编译过程不仅生成字节码,还要包含常量、变量、占用栈的空间等,Pyton中编译过程生成code对象PyCodeObject。将PyCodeObject写入二进制文件,即.pyc。


有必要则写入A.pyc指的是该.py是否只运行一次,如果import的模块,肯定会生成.pyc。

2、PyCodeObject对象与.pyc文件

Python解释器将.py程序编译为PyCodeObject对象,具体过程与编译原理类似。

typedef struct {    PyObject_HEAD    int co_argcount;           // Code Block的参数的个数,比如说一个函数的参数    int co_nlocals;                    // Code Block中局部变量的个数    int co_stacksize;          // 执行该段Code Block需要的栈空间    int co_flags;                      // N/A    PyObject *co_code;         // Code Block编译所得的byte code,以PyStringObject的形式存在    PyObject *co_consts;       // PyTupleObject对象,保存Code Block中的常量    PyObject *co_names;                // PyTupleObject对象,保存Code Block中的所有符号    PyObject *co_varnames;     // Code Block中局部变量名集合    PyObject *co_freevars;     // 实现闭包所需东西    PyObject *co_cellvars;  // Code Block内部嵌套函数所引用的局部变量名集合    PyObject *co_filename;     // Code Block所对应的.py文件的完整路径    PyObject *co_name;         // Code Block的名字,通常是函数名或类名    int co_firstlineno;                // Code Block在对应的.py文件中的起始行    PyObject *co_lnotab;       // byte code与.py文件中source code行号的对应关系,以PyStringObject的形式存在    void *co_zombieframe;    PyObject *co_weakreflist;} PyCodeObject;

一个Code Block生成一个PyCodeObject,进入一个名字空间成为进入一个Code Block。如下.py文件编译完成后会生成三个PyCodeObject,一个对应整个.py文件一个对应Class A,一个对应def Fun。实际这三个code对象是嵌套的,后两个code对象位于第一个code对象的co_consts属性中。其实,字节码位于co_code中。

class A:        passdef Fun():        passa = A()Fun()

pyc文件包括三部分:

(1)四字节的Magic int,表示pyc版本信息

(2)四字节的int,是pyc产生时间,若与py文件时间不同会重新生成

(3)序列化了的PyCodeObject对象。

3、pyc文件的生成

写入pyc文件的函数包括以下几个步骤:

PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION);      // 写入版本信息PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);                        // 写入时间信息PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);     // 写入PyCodeObject对象

关键在于code对象的写入:

{    WFILE wf;    wf.fp = fp;        ……    w_object(x, &wf);}

用到了一个WFILE结构体,可以认为是对FILE *fp 的一个封装:

typedef struct {    FILE *fp;    int error;    int depth;    PyObject *strings; // 存储字符串,写入时以dict形式,读出时以list形式} WFILE;

关键在于w_object()函数:

static void w_object(PyObject *v, WFILE *p){        if (v == NULL)   ……        else if (PyInt_CheckExact(v)) ……        else if (PyFloat_CheckExact(v)) ……        else if (PyString_CheckExact(v)) ……        else if (PyList_CheckExact(v)) ……}

w_code实质为根据不同的对象类型选取不同的策略,例如tuple对象:

else if (PyTuple_CheckExact(v)) {        w_byte(TYPE_TUPLE, p);        n = PyTuple_Size(v);        W_SIZE(n, p);        for (i = 0; i < n; i++)             w_object(PyTuple_GET_ITEM(v, i), p);

而所有类型最终可分解为写入数值与写入字符串两种操作,涉及以下几部分:

#define w_byte(c, p) putc((c), (p)->fp)      // 用于写入类型static void w_long(long x, WFILE *p){  // 用于写入数字      w_byte((char)( x      & 0xff), p);     // 实质为用四个字节存储一个数字    w_byte((char)((x>> 8) & 0xff), p);    w_byte((char)((x>>16) & 0xff), p);    w_byte((char)((x>>24) & 0xff), p);}static void w_string(char *s, int n, WFILE *p){      //用于写入字符串    fwrite(s, 1, n, p->fp);}

由于序列化写入文件后丢失了结构信息,故写入每个对象时写入类型信息w_byte:

#define TYPE_INT                'i'#define TYPE_LIST               '['#define TYPE_DICT               '{'#define TYPE_CODE               'c'

由于Python皆对象,w_object(PyObject*)便可针对不同类型选取不同写入方法,不断细分,最终分解为PyInt_Object或PyString_Object,利用w_long或w_string写入。

数字比较简单:

else if (PyInt_CheckExact(v)) {    w_byte(TYPE_INT, p);    w_long(x, p);}

字符串则比较复杂:

 else if (PyString_CheckExact(v)) {        if (p->strings && PyString_CHECK_INTERNED(v)) {            PyObject *o = PyDict_GetItem(p->strings, v);     // 获取在strings中的序号            if (o) {                      // inter对象的非首次写入                long w = PyInt_AsLong(o);                w_byte(TYPE_STRINGREF, p);                w_long(w, p);                goto exit;            }            else {                             // intern对象的首次写入                int ok;                ok = o && PyDict_SetItem(p->strings, v, o) >= 0;                Py_XDECREF(o);                w_byte(TYPE_INTERNED, p);            }        }        else {                                     // 写入普通string            w_byte(TYPE_STRING, p);        }        n = PyString_GET_SIZE(v);        W_SIZE(n, p);        w_string(PyString_AS_STRING(v), n, p);    }               

(1)若写入普通字符串,写入字符串类型信息"S",然后写入字符串长度及string值。

(2)若写入inter字符串,先到WFILE的strings中查找:

(a)若找到,则写入引用类型信息"R",然后写入序号

(b)若未找到,创建对象放入strings,并写入intern类型信息"t",然后写入字符串长度及string值。
若依次写入"efei"、"snow"、"efei",则会如下:


从pyc文件读入时,依靠list,那么序号就可以利用上了。

"Python编译结果之如何理解code对象与pyc文件"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

对象 文件 字符 字符串 编译 信息 类型 过程 生成 字节 不同 函数 变量 形式 局部 序号 数字 时间 空间 结果 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 厦门中拓互联网络科技有限公司 重庆互联网络科技 中资互联网科技 青岛互联网科技公司 成都互联网科技公司 唐信互联网科技 大连 深圳卡尔迅互联网科技有限公司怎么样 科技赋能互联网健康 团飞科技与伯堂互联网服务平台 宝灵互联网科技有限公司 中国科技创新与世界互联网大会 天津腾达互联网科技有限公司 四川慕妮娅互联网科技有限公司 江苏互联网智能科技软件 厦门江牛科技互联网 上海创道互联网络科技有限公司 工业互联网科技成果转化 广东鹅鹅鹅互联网科技有限公司 重庆科技产业互联网有哪些 互联网企业和网络科技有限公司 上海挚品互联网科技有限公司 互联网科技开发公司 互联网科技视频素材 互联网金融和金融科技 互联网科技公司做什么 阿里巴巴算科技企业还是互联网 顶级互联网科技成果有哪些 智腾互联网科技有限公司 湖南一路畅行互联网科技 湖北辰鑫科技互联网
0