最近想学习下 Python 的源码,希望写个系列博客,记录的同时督促自己学习。
Python 源码目录
从 Python.org 中下载源代码压缩包并解压,我下载的是 Python2.7.12,解压后:
对于主要的文件夹做出介绍:
Include: 包含 Python 提供的所有头文件,如果需要自己使用 C 或者 C++ 编写自定义模块扩展 Python,就需要用到这里的头文件;
Lib: 包含 Python 自带的所有标准库,全部由 Python 语言编写;
Modules:包含了所有使用 C 语言编写的模块;
Parser:Python 解释器中的 Scanner 和 Parser(对 Python 代码进行词法分析和语法分析),这里还包含一些能根据 Python 语言的语法自动生成 Python 词法和语法功能的工具;
Objects:所有 Python 的内建对象;
Python:Python 解释器中的 Compiler 和执行引擎部分,是 Python 运行的核心所在!!!
Python 中的对象
对象可以说是 Python 最核心的一个概念,在 Python 的世界里,一切都是对象。我们知道 Python 是由 C 编写的,C 并不是一个面向对象语言,而由 C 编写的 Python 确实面向对象的,那么它的对象机制是如何实现的呢?
对于人的思维,对象是可以形象描述的,但是对于计算机而言,对象是一个抽象的概念,计算机所知道的一切都是字节。关于对象,通常的说法是,对象是数据以及基于这些数据的操作的集合,在计算机中,一个对象实际就是把一片被分配的内存空间,且这片内存在更高层次可作为一个整体,这个整体就是一个对象。
在 Python 中,对象就是 C 中的结构体在堆上申请的一块内存。
对象机制的基石——Pyobject
在 Python 中,所有的东西都是对象,而所有的对象都拥有一些相同的内容,Python 中的这些内容都是在 object.h 中的 Pyobject 中定义的。
- typedef struct _object {
- PyObject_HEAD
- }
- PyObject;
定长对象和变长对象
Python 除了 Pyobject 对象之外,还有一个表示这类对象的结构体 pyVarObject,pyVarobject 其实就是对 pyobject 的一个扩展。
那么站在源码的角度上分析,变长对象是在 pyVarobject 中添加了可变长度数据的对象,也就是 ob_size,定义了所容纳元素的个数。定长对象和变长对象的区别是:定长对象的不同对象占用的内存大小是一样的,变长对象的不同对象占用的内存可能是不一样的。比如整数对象'1'和'100'占用的内存大小都是 sizeof(PyIntObject),而字符串对象"me"和"you" 占用的内存大小就不一样。
Python 对象的多态性
面向对象中一个重要的特性是多态,那么 Python 是如何实现多态的呢?
在 Python 创建一个对象时,会分配内存,进行初始化,然后 Python 内部会使用一个 PyObject * 变量来保存和维护这个对象,Python 中的所有对象均是如此。比如创建一个 PyIntObject 对象(整数对象),不是通过 PyIntObject * 变量来保存和维护这个对象,而是通过 PyObject *,正因为所有对象均如此,所以 Python 内部各个函数之间传递的都是一种范型指针(Pyobject*),而这个指针所指的对象究竟是什么类型的,我们是不知道的,只能从指针所指对象的 ob_type 域动态进行判断,而正是这个域,Python 实现了多态。
引用计数
和 C 或 C++ 不同,Python 选择使用语言本身负责内存的管理和维护,也就是垃圾收集机制,代替程序员进行繁重的内存管理工作,而引用计数刚好是 Python 垃圾收集机制的一部分。
Python 通过对一个对象的引用计数来管理和维护对象在内存中的存在与否。Python 中的一切皆是对象,在所有的对象中有一个 ob_refcent 变量,维护这对象的引用计数,从而也决定该对象的创建与消亡。
在 Python 中,使用 Py_INCREF(op) 和 Py_DECREF(op) 两个宏来增加和减少一个对象的引用计数,在每一个对象创建的时候,Python 提供了一个 Py_NewReference(op) 宏来将对象的引用计数初始化为 1。
当一个对象的引用计数为 0 时,与该对象对应的析构函数将被调用, 但是调用析构函数并不一定是调用 free 释放内存空间,为了避免频繁的申请、释放内存空间,Python 中使用的是内存对象池,维护一定大小的内存对象池,调用析构函数时,对象占用的空间将归还到内存池中。
Python 中的整数对象
在 Python 的所有对象中,整数对象最简单且使用最频繁,故我们首先学习整数对象。关于整数对象的源码在 Objects.intobjects.c 中,整数对象是通过 PyIntObject 对象来完成的,在创建一个 PyIntObject 对象之后,就再也不能改变该对象的值了。定义为:
- typedef struct {
- prObject_HEAD;
- long ob_ival;
- }
- PyIntObject;
可以看到,Python 中的整数对象其实是对 C 中 long 的一个简单封装,也就是整数对象维护的数据的长度在对象定义时就已经确定了,就是 C 中 long 的长度。
在 Python 中,整数的使用是很广泛的,对应的,它的创建和释放也将会很频繁,那么如何设计一个高效的机制,使得整数对象的使用不会成为 Python 的瓶颈?在 Python 中是使用整数对象的缓冲池机制来解决此问题。使用缓冲池机制,那意味着运行时的整数对象并不是一个个独立的,而是相关联结成一个庞大的整数对象系统了。
小整数对象
在实际的编程中,数值比较小的整数,比如 1,2, 等等,这些在程序中是频繁使用到的,而 Python 中,所有的对象都存活在系统堆上,也就是说,如果没有特殊的机制,对于小整数对象,Python 将一次次的 malloc 在堆上申请空间,然后 free,这样的操作将大大降低了运行效率。
那么如何解决呢?Python 中,对小整数对象使用了对象池技术。
那么又有一个问题了,Python 中的大对象和小对象如何区分呢?嗯,Python 中确实有一种方法,用户可以调整大整数和小整数的分界点,从而动态的确定小整数的对象池中应该有多少个小整数对象,但是调整的方法只有自己修改源代码,然后重新编译。
大整数对象
对于小整数,小整数对象池中完全的缓存 PyIntObject 对象,对于其它对象,Python 将提供一块内存空间,这些内存空间将由这些大整数轮流使用,也就是谁需要的时候谁使用。
比如,在 Python 中有一个 PyIntBlock 结构,维护了一块内存,其中保存了一些 PyIntObject 对象,维护对象的个数也可以做动态的调整。在 Python 运行的某个时刻,有一些内存已经被使用,而另一些内存则处于空闲状态,而这些空闲的内存必须组织起来,那样,当 Python 需要新的内存时,才能快速的获得所需的内存,在 Python 中使用一个单向链表 (free_list)来管理所有的空闲内存。
- #define BLOCK_SIZE 1000
- /* 1K less typical malloc overhead */
- #define BHEAD_SIZE 8
- /* Enough for a 64-bit pointer */
- #define N_INTOBJECTS((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject)) struct _intblock {
- struct _intblock * next;
- PyIntObject objects[N_INTOBJECTS];
- };
- typedef struct _intblock PyIntBlock;
- static PyIntBlock * block_list = NULL;
- static PyIntObject * free_list = NULL;
创建
现在, 我们已经大体知道 Python 中整数对象系统在内存是一种怎样的结构了,下面将介绍一个个 PyIntObject 是怎样的从无到有的产生。主要分为两步:
如果小整数对象池机制被激活,则尝试使用小整数对象池;如果不能使用小整数对象池,则使用通用整数对象池。
以 PyInt_FromLong 说明:
- PyObject * PyInt_FromLong(long ival) {
- register PyIntObject * v;#
- if NSMALLNEGINTS + NSMALLPOSINTS > 0
- if ( - NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
- v = small_ints[ival + NSMALLNEGINTS];
- Py_INCREF(v);#ifdef COUNT_ALLOCS
- if (ival >= 0) quick_int_allocs++;
- else quick_neg_int_allocs++;#endif
- return (PyObject * ) v;
- }#endif
- if (free_list == NULL) {
- if ((free_list = fill_free_list()) == NULL) return NULL;
- }
- /* Inline PyObject_New */
- v = free_list;
- free_list = (PyIntObject * ) Py_TYPE(v);
- PyObject_INIT(v, &PyInt_Type);
- v - >ob_ival = ival;
- return (PyObject * ) v;
- }
今天的学习就到这里,明天继续学习分析~
来源: http://www.cnblogs.com/ybjourney/p/6139461.html