《python源代码剖析》笔记 Python的编译结果
本文为senlie原创。转载请保留此地址:http://blog.csdn.net/zhengsenlie
1.python的运行过程
1)对python源码进行编译。产生字节码
2)将编译结果交给python虚拟机。由虚拟机依照顺序一条一条地运行字节码,产生运行结果
2.Python编译器的编译结果——PyCodeObject对象
Python编译器的编译结果中包括了字符串、常量值、字节码等在源码中出现的一切实用的静态信息。
在Python执行期间,这些静态信息被PyCodeObject对象中
在Python执行结束后。这些信息会被存储在pyc文件里
PyCodeObject对象和pyc文件是Python对源文件编译结果的两种不同存在形式
3.Python源代码中的PyCodeObject
/* Bytecode object */
typedef struct {
PyObject_HEAD
int co_argcount; /* 位置參数个数*/
int co_nlocals; /* 局部变量个数,包含位置參数个数*/
int co_stacksize; /* 须要的栈空间 */
int co_flags; /* CO_..., see below */
PyObject *co_code; /* 字节码指令序列,以PyStringObject形式存在 */
PyObject *co_consts; /* PyTupleObject对象,保存全部的常量 */
PyObject *co_names; /* PyTupleObject对象。保存全部符号 */
PyObject *co_varnames; /* 局部变量名集合 */
PyObject *co_freevars; /* 实现闭包须要用到的东西 */
PyObject *co_cellvars; /* 内部嵌套函数所引用的局部变量名集合 */
/* The rest doesn't count for hash/cmp */
PyObject *co_filename; /* Code Block所相应的.py文件的完整路径 */
PyObject *co_name; /* Code Block的名字,一般是函数名或类名 */
int co_firstlineno; /* Code Block所相应的.py文件的起始行 */
PyObject *co_lnotab; /* 字节码指令与.py文件里source code行号的相应关系。以PyStringObject的等式存在 */
void *co_zombieframe; /* for optimization only (see frameobject.c) */
PyObject *co_weakreflist; /* to support weakrefs to code objects */
} PyCodeObject;
Code Block:当进入一个新的名字空间,或者说作用域的时候,就算是进入了一个新的Code Block:当进入一个新的名字空间。或者说作用域的时候,就算是进入了一个新的
Code Block。一个 Code Block相应一个 PyCodeObject
名字空间是符号的上下文环境。名字空间链是多个名字空间嵌套在一起。
在Python中,module、类、函数都相应着一个独立的名字空间
#会产生三个 PyCodeObject。分别相应整个文件。class A和 def Fun
class A:
pass
def Fun():
pass
a = A()
Fun()
3.pyc文件
pyc文件里包括了三部分独立的信息:
Python的magic number --> 保证Python的兼容性
pyc文件的创建时间 --> 能够使Python自己主动将pyc文件与最新的py文件进行同步
PyCodeObject对象
将内存中的PyCodeObject对象写入到pyc文件,须要下面几个函数
w_byte
w_long
w_string
PyMarshal_WriteObjectToFile会调用w_object,w_object会遍历 PyCodeObject中的全部域,
将这些域依次写入。
写入终于归结为两种形式:对数值的写入和对字符串的写入
static void w_object(PyObject *v, WFILE *p)
{
//……
else if (PyCode_Check(v))
{
PyCodeObject *co = (PyCodeObject *)v;
w_byte(TYPE_CODE, p);
w_long(co->co_argcount, p);
w_long(co->co_nlocals, p);
w_long(co->co_stacksize, p);
w_long(co->co_flags, p);
w_object(co->co_code, p);
w_object(co->co_consts, p);
w_object(co->co_names, p);
w_object(co->co_varnames, p);
w_object(co->co_freevars, p);
w_object(co->co_cellvars, p);
w_object(co->co_filename, p);
w_object(co->co_name, p);
w_long(co->co_firstlineno, p);
w_object(co->co_lnotab, p);
}
//……
}
w_object在写入对象之前会先写入TYPE_LIST、TYPE_CODE或者TYPE_INT标识,它们对
pyc文件的再次载入具有至关关键的数据。Python在pyc文件里发现这种标识,则预示着
一个对象的结束,新对象的開始。并且也知道了对象的类型。
4.向pyc文件里写入字符串
写入过程中的结构体WFILE
typedef struct {
FILE *fp;
PyObject *strings; //在写入时指向dict,在读出时指向list
} WFILE;
WFILE中的strings在marshal的时候指向一个PyDictObject对象(PyStringObject,PyIntObject)
//w_object对于字符串的处理
else if (PyString_CheckExact(v)) {
if (p->strings && PyString_CHECK_INTERNED(v)) {
//[1]:获得 PyStringObject对象在strings中的序号
PyObject *o = PyDict_GetItem(p->strings, v);
//[2]:intern字符串的非首次写入
if (o) {
long w = PyInt_AsLong(o);
w_byte(TYPE_STRINGREF, p);
w_long(w, p);
goto exit;
}
//[3]:intern字符串的首次写入
else {
int ok;
o = PyInt_FromSsize_t(PyDict_Size(p->strings));
ok = o &&
PyDict_SetItem(p->strings, v, o) >= 0;
Py_XDECREF(o);
if (!ok) {
p->depth--;
p->error = WFERR_UNMARSHALLABLE;
return;
}
w_byte(TYPE_INTERNED, p);
}
}
//[4]:写入普通字符串
else {
w_byte(TYPE_STRING, p);
}
//写入字符串
w_pstring(PyBytes_AS_STRING(v), PyString_GET_SIZE(v), p);
}
//...
怎么确定一个字符串要不要intern?
写入pyc文件时,strings是dict类型
从pyc文件里读取的时候,strings是list类型
5.一个PyCodeObject,多个PyCodeObject
PyCodeObject中的co_consts是嵌套的PyCodeObject的藏身之处
6.Python的字节码
104条字节码
STOP_CODE()
Indicates end-of-code to the compiler, not used by the interpreter.
NOP()
Do nothing code. Used as a placeholder by the bytecode optimizer.
POP_TOP()
Removes the top-of-stack (TOS) item.
ROT_TWO()
Swaps the two top-most stack items.
ROT_THREE()
Lifts second and third stack item one position up, moves top down to position three.
ROT_FOUR()
Lifts second, third and forth stack item one position up, moves top down to position four.
//...
《python源代码剖析》笔记 Python的编译结果的更多相关文章
- Python源代码剖析笔记3-Python运行原理初探
Python源代码剖析笔记3-Python执行原理初探 本文简书地址:http://www.jianshu.com/p/03af86845c95 之前写了几篇源代码剖析笔记,然而慢慢觉得没有从一个宏观 ...
- 《python源代码剖析》笔记 Python虚拟机框架
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1. Python虚拟机会从编译得到的PyCodeObject对象中依次读入每一条字节码指令 ...
- 《python源代码剖析》笔记 python虚拟机中的函数机制
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.Python虚拟机在运行函数调用时会动态地创建新的 PyFrameObject对象, 这 ...
- 《python源代码剖析》笔记 python环境初始化
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/zhsenl/article/details/33747209 本文为senlie原创.转载请保留此地 ...
- 《python源代码剖析》笔记 python中的List对象
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.PyListObject对象 --> 变长可变对象,可看作vector<Py ...
- 《python源代码剖析》笔记 python中的Dict对象
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.PyDictObject对象 --> C++ STL中的map是基于RB-tre ...
- Python知识点入门笔记——Python文件操作、异常处理及random模块使用
文件是存储在外部介质的数据集合,通常可以长久保存,前提是介质不易损坏 Python的绝对路径写法: E:\\编程学习资料\\爬取某社区高清无码大图.py E:/编程学习资料/爬取某社区高清无码大图.p ...
- Python知识点入门笔记——Python的基本数据类型
Python的数字分为4种类型:整数(int).浮点数(float).布尔值(bool).复数(complex). type()函数可以知道数据的类型,如type(233)是int型,type(233 ...
- 流畅的python第九章笔记 python风格的python
9.1对象表示形式 __repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员. 我们打印下面的A是默认输出这个对象的类型,我们对B进行了修改_ ...
随机推荐
- DFS:POJ3620-Avoid The Lakes(求最基本的联通块)
Avoid The Lakes Time Limit: 1000MS Memory Limit: 65536K Description Farmer John's farm was flooded i ...
- python中os模块讲解
本文主要介绍一些os模块常用的方法: 先看下我的文件目录结构 D:\LearnTool\pycode\part1 在此目录下的文件如下: abcd.py demo1.1.py demo1.2.py z ...
- if-else优化
过多if-else分支的优化 超过3个就应该去优化,说if-else过多的分支可以使用switch或者责任链模式等等方式来优化.确实,这是一个小问题,不过我们还是可以整理一下这个小问题的重构方式. ...
- Python第三方库之openpyxl(8)
Python第三方库之openpyxl(8) 饼图 饼图将数据绘制成一个圆片,每个片代表整体的百分比.切片是按顺时针方向绘制的,0在圆的顶部.饼图只能取一组数据.该图表的标题将默认为该系列的标题. 2 ...
- spring常用的注解
一.使用注解之前要开启自动扫描功能,其中base-package为需要扫描的包(含子包). <context:component-scan base-package="cn.test& ...
- ZingChart 图表插件
ZingChart提供了一个丰富的API,用于通过重新绘制绘图(重新加载) ,加载新数据(setseriesdata),修改现有图表(modifyplot), 放大数据范围(zoomto),切换各种交 ...
- 九度oj 题目1172:哈夫曼树
题目描述: 哈夫曼树,第一行输入一个数n,表示叶结点的个数.需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的值与权值的乘积之和. 输入: 输入有 ...
- 周赛Problem 1108: 蛋糕(二分)
1108: 蛋糕 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 17 Solved: 4 Description 杨神打代码打得有点疲倦,于是他想要 ...
- [BZOJ1576] [Usaco2009 Jan]安全路经Travel(堆优化dijk + (并查集 || 树剖))
传送门 蒟蒻我原本还想着跑两边spfa,发现不行,就gg了. 首先这道题卡spfa,所以需要用堆优化的dijkstra求出最短路径 因为题目中说了,保证最短路径有且只有一条,所以可以通过dfs求出最短 ...
- 作业调度方案(codevs 1156)
题目描述 Description 我们现在要利用m台机器加工n个工件,每个工件都有m道工序,每道工序都在不同的指定的机器上完成.每个工件的每道工序都有指定的加工时间. 每个工件的每个工序称为一个操作, ...