Python学习之pyc文件与code对象

本文和大家分享的主要是python中的pyc文件与code对象相关内容,一起来看看吧,希望对大家学习python有所帮助。

python对源程序编译结果是生成一个 .pyc 文件. python对 .py 文件的编译结果是字节码, 为了能复用而不需要重新编译才有了写成 .pyc 文件. 对于解释器来说 PyCodeObject 对象才是真正编译结果, pyc文件只是这个对象在硬盘上的表现形式.

PyCodeObject

[code.h]typedef struct {

PyObject_HEAD

int co_argcount;        /* #arguments, except *args */

int co_kwonlyargcount;  /* #keyword only arguments */

int co_nlocals;     /* #local variables */

int co_stacksize;       /* #entries needed for evaluation stack */

int co_flags;       /* CO_..., see below */

int co_firstlineno;   /* first source line number */

PyObject *co_code;      /* instruction opcodes */

PyObject *co_consts;    /* list (constants used) */

PyObject *co_names;     /* list of strings (names used) */

PyObject *co_varnames;  /* tuple of strings (local variable names) */

PyObject *co_freevars;  /* tuple of strings (free variable names) */

PyObject *co_cellvars;      /* tuple of strings (cell variable names) */

void *co_extra;

} PyCodeObject;

编译器在对源代码进行编译的时候, 每一个 Code Block 会创建一个 PyCodeObject 对象与这个代码段相对应. 代码段的范围可大可小. 可以是整个py文件, 可以是class, 可以是函数.

访问PyCodeObject对象

在python中, 有与c一级的对PyCodeObject简单包装, code对象, 可以访问到PyCodeObject的各个域.

>>> source = open(’db.py’).read()>>> co = compile(source, ’db.py’, ’exec’)>>> type(co)

<class ’code’>>>> co.co_names

(’pymysql’, ’config’, ’threading’, ’RLock’, ’Lock’, ’create_table_template’, ’ob

ject’, ’Model’, ’str’, ’m’)

写入文件 PyMarshal_WriteObjectToFile

向pyc文件写入数据主要是这几个, 有删减:

[marshal.c]

typedef struct {

FILE *fp;

int depth;

PyObject *str;

char *ptr;

char *end;

char *buf;

_Py_hashtable_t *hashtable;

int version;

} WFILE;

#define w_byte(c, p) do {

if ((p)->ptr != (p)->end || w_reserve((p), 1))

*(p)->ptr++ = (c);

} while(0)

static void w_flush(WFILE *p)

{

assert(p->fp != NULL);

fwrite(p->buf, 1, p->ptr - p->buf, p->fp);

p->ptr = p->buf;

}

这是文件写入定义的基本结构, fp指向最后要写入的文件, w_byte(c, p) 则是一个简单的封装, 以字节为单位的复制到p->ptr先行区中. w_flush(WFILE *p) 则是将缓冲区 p->buf 写到文件中.p->ptr也就是准备写到文件中的增量部分.

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(const char *s, Py_ssize_t n, WFILE *p)

{

Py_ssize_t m;

if (!n || p->ptr == NULL)

return;

m = p->end - p->ptr;

if (p->fp != NULL) {

if (n <= m) {

memcpy(p->ptr, s, n);

p->ptr += n;

}

else {

w_flush(p);

fwrite(s, 1, n, p->fp);

}

}

else {

if (n <= m || w_reserve(p, n - m)) {

memcpy(p->ptr, s, n);

p->ptr += n;

}

}

}

如在调用 PyMarshal_WriteLongToFile 时, 会调用 w_long , 数据将会一个字节字节的写入到文件中. 而调用PyMarshal_WriteObjectToFile 也会调用 w_object , 这个函数比较长,就不列出来了.

为了区分写入的类型, 在写入文件前会做一个动作,就是先将待写入的对象类型写进去:

[marshal.c]

#define TYPE_NULL               ’0’

#define TYPE_NONE               ’N’

#define TYPE_FALSE              ’F’

#define TYPE_TRUE               ’T’

#define TYPE_STOPITER           ’S’

#define W_TYPE(t, p) do {

w_byte((t) | flag, (p));

} while(0)

这个对象类型的标识对读取pyc文件至关重要, 因为对象写入pyc文件后, 所有数据都变成字节流, 类型信息丢失. 有了这个标识, 当读取这样的标识时, 则预示着上一个对象结束, 新的对象开始, 也能知道新对象是什么类型的.

内部也有机制处理共享对象, 减少字节码中冗余信息. 共享类型的属于 TYPE_INTERNED .

加载pyc文件 PyMarshal_ReadObjectFromFile

看一下加载pyc文件的过程, 让pyc文件理解更加深刻:

PyObject * PyMarshal_ReadObjectFromFile(FILE *fp)

{

RFILE rf;

PyObject *result;

rf.fp = fp;

rf.readable = NULL;

rf.current_filename = NULL;

rf.depth = 0;

rf.ptr = rf.end = NULL;

rf.buf = NULL;

rf.refs = PyList_New(0);

if (rf.refs == NULL)

return NULL;

result = r_object(&rf);

Py_DECREF(rf.refs);

if (rf.buf != NULL)

PyMem_FREE(rf.buf);

return result;

}

从 r_object 开始就开始从pyc文件中读入数据, 并创建PyCodeObject对象, 这个 r_object 是对 w_object 的逆运算. 当读到 TYPE_INTERNED 后, 会将其后面的字符串读入, 将这个字符串进行intern操作.

来源:栖迟於一丘

时间: 2025-01-15 16:07:18

Python学习之pyc文件与code对象的相关文章

Python学习笔记_Chapter 6定制数据对象

1. 有用的BIF a. 判断字符串中是否包含子字符串 1 if s_a in s_b: b. pop() 描述:从指定的列表位置删除并返回一个数据项. 1 (sarah_name,sarah_dob)=l_rah.pop(0),l_rah.pop(0) 2 #pop(0)中0位置为list中第一个数据项 3 #第一次执行pop赋值给sarah_name c. strip() 输入的是字符串,返回的是列表 d.open 读文件时可以多种方式打开文件,取出的数据是不同的,可以是文本也可以是二进制.

python学习笔记九——文件与目录

1.python进行文件读写的函数是open或file类 mode:r  只读 r+   读写 w  写入,先删除原文件,再重新写入,如果文件没有则创建 w+  读写,先删除原文件,再重新写入,如果文件没有则创建(可写入和输出) a  写入,在文件末尾追加新的内容,文件不存在则创建 a+  读写,在文件末尾追加新的内容,文件不存在则创建 b  打开二进制文件,可与r,w,a,+结合使用 U  支持所有的换行符号,"\r","\n","\r\n"

转载-python学习笔记之文件I/O

Python 文件I/O 本章只讲述所有基本的的I/O函数,更多函数请参考Python标准文档. 打印到屏幕 最简单的输出方法是用print语句,你可以给它传递零个或多个用逗号隔开的表达式.此函数把你传递的表达式转换成一个字符串表达式,并将结果写到标准输出如下: #!/usr/bin/python # -*- coding: UTF-8 -*- print "Python 是一个非常棒的语言,不是吗?"; 你的标准屏幕上会产生以下结果: Python 是一个非常棒的语言,不是吗? 读取

python学习笔记(文件)

打开文件 open函数使用一个文件名作为唯一的强制参数,返回一个文件对象 语法: file object = open(file_name [, access_mode][, buffering]) 各个参数的细节如下: file_name:file_name变量是一个包含了你要访问的文件名称的字符串值. access_mode:access_mode决定了打开文件的模式:只读,写入,追加等.所有可取值见如下的完全列表.这个参数是非强制的,默认文件访问模式为只读(r). buffering:如果

转载-Python学习笔记之文件读写

Python 文件读写 Python内置了读写文件的函数,用法和C是兼容的.本节介绍内容大致有:文件的打开/关闭.文件对象.文件的读写等. 本章节仅示例介绍 TXT 类型文档的读写,也就是最基础的文件读写,也需要注意编码问题:其他文件的读写及编码相关详见专题的博文. open()   close()     with open(...) as ... 看以下示例就能了解 Python 的 open() 及 close() 函数.这边调用 read()方法可以一次读取文件的全部内容,Python把

Python学习总结之文件操作

从本次随笔开始,陆续总结下自己在学习Python中各个模块的一些总结.最近一直在学习<Python核心编程>,发现如果只是翻书的话,翻一遍就忘记,所有,现在争取在一个月内,把Python常用的一些基础知识做一个梳理和总结. 本次总结文件和输入输出的一些操作,参考书目<Python 核心编程 第二版>. 一,文件的操作 文件的入口是由内建函数 open()和file()来提供初始化的操作.这两个内建函数操作基本上一样,可以互用,而且大部分习惯来说,还是用open()比较多一些. op

Python学习笔记之文件和流

打开文件:open(name[,mode[,buffering]]),返回一个文件对象,模式(mode)和缓冲(buffering)是两个可选参数. 假设有一个名为somefile.txt的文件,存储路径为c:\text,打开方式如下:f = open(r'C:\text\somefile.txt') mode参数:如果open函数只带一个文件名参数,可以获得能读取文件内容的文件对象,如果要进行写操作,则必须要提供一个模式操作显式声明. 值 描述 'r' 读模式 'w' 写模式 'a' 追加模式

Python学习篇之文件处理

Python文件打开方式: file_object = open(file_name, access_mode='r', buffering=-1) access_mode    说明 'r'            只读方式打开,文件必须存在 'w'            只写方式打开,文件不存在创建文件,文件存在则清空文件内容 'a'            追加方式打开,文件不存在创建文件 'r+'/'w+'      读写方式打开,'r+'源文件如果有内容不会被清空,但是写入内容时会从文件第

Python学习笔记六--文件和输入输出

6.1文件对象 所有Python对文件的操作都是基于对文件对象的操作.那么就从文件对象的创建说起.open()[file()]提供初始化输入输出的接口.open()成功打开文件时会返回一个文件对象. open()方法的语法: file_object=open(filename,access_mode,buffering) filename,表示要打开的文件名的字符串,可以是相对路径也可以是绝对路径. access_mode,表示打开方式.常见有'r'.'w'.'a',分别表示读模式,写模式,追加