从网络上下载《 Python 源码剖析》一书, 好好看一下别人的源码, 顺便笔记一下免得忘记.
(作者: 陈儒, 副标题: 深度探索动态语言核心技术, 大概是 2008 年出版)
书中所分析的 Python 版本为 2.5, 我看了一下 python 官网, 当前最新版本为 3.5.1, 幸好我比较喜欢考古,
看看过去的 python 版本也挺好. 有机会就要多读点别人的源码好好学习, 趁着没任务有时间.
第0章准备工作, 讲如何编译 python, 我想这不是重点, 简单看一下就不做很多笔记了.
关于 Python 总体架构有一张图, 需要记录一下, 看的时候可以按图索骥, 帮助省下很多力气:
File Groups: Core Modules, Library, User-defined Modules
Python Core: Scanner, Parser, Compiler, Code Evauator?
Runtime Environment: Object/Type Structures, Memory Allocator, Current State of Python
================================================================
在 Python 的世界中, 一切都是对象, 如整数,字符串. 类型也是一种对象. 类和对象两个概念在 python 中都是
通过 python 内的对象来实现的. 有内建类型对象, 如 int, string, dict.
Python 自 1989 年开始, 实现语言为 ANSI C.
在 Python 中, 对象是在 C 堆上分配的一块(连续)内存, 一般不是静态的, 也不在堆栈空间. 内建类型对象是静态
初始化的 一个例外. 对象一旦创建, 内存大小即不可变. (这里暗示 GC 不会移动对象)
对象机制的基石是 PyObject. 所有对象拥有的相同的内容定义在 Include/object.h 中 struct PyObject:
// object.h -- Object and type object interface // 此文件中的大段英文注解, 如果翻译过来, 就和刚才看到的中文几乎一样. struct PyObject { int ob_refcnt; PyTypeObject *ob_type; // 可认为是 vfptr 指向虚函数表. };
这里字段 ob_refcnt 实现引用计数机制. 这与 Python 的内存管理机制有关, Python 实现的是基于引用计数的垃圾
收集机制. (稍后关注下如何垃圾回收, 如果循环引用的话)
字段 ob_type 指向 _typeobject 结构, 用于表示此对象的类型 (即含该类型的描述数据).
对于整数对象, 在文件 intobject.h 中:
// 我们用 C++ 继承语法来写语义. struct PyIntObject : public PyObject { // 实际是 PyObject_HEAD 在最前面. long ob_ival; };
其它类型的对象如 string, list, dict 也类似, 在 PyObject 的头部后面添加自己的信息.
另一种包含可变长数据的对象头部大致是 (位于 object.h 中):
// 这里将 PyObject 放在结构最前面的方式, 语义一致即可. struct PyVarObject { PyObject _base; int ob_size; }
书上说 string, list 等使用此 PyVarObject 头部.
类型对象 _typeobject 大致如下 (位于 object.h 中):
struct PyTypeObject { PyVarObject _base; // 头部. const char *tp_name; // 类名字. size_t tp_basicsize, tp_itemsize; // for allocation // 很多很多各种 methods 的定义 ... 如: destructor tp_dealloc; // dtor(), 可认为是虚函数表. printfunc tp_print; // 可看做是 toString() ... // 总之是这个类型的描述数据, 和处理的函数. 目测不下 30 个字段. ... };
对象的创建
两种方法: 1. Python C API; 2. 通过类型对象 PyInt_Type.
API 的两种类型:
1. 范型 API, 或称为 AOL (Abstract Objct Layer). 形式为 PyObject_***.
创建整数对象例子: PyObject *intobj = PyObject_New(PyObject, &PyInt_Type);
(可以想象为 java/c# 中的 Integer.Class.new() 方式)
2. 类型相关 API, 或称为 COL (Concrete Object Layer). 对应该类型对象使用.
如创建整数对象: PyObject *intobj = PyInt_FromLong(10);
(可以想象为 Integer.from_long(10) 方式)
在 PyTypeObject 中有 newfunc tp_new 字段用于创建一个该类型的对象;
PyTypeObject *tp_base 表示此类型的基类. 如 int (PyInt_Type) 的基类为 PyBaseObject_Type.
在这些函数中, 有三组非常重要的操作族, tp_as_[num|seq|map]. 对应如 PyNumberMethods:
struct PyNumberMethods { binaryfunc nb_add; // 定义二元运算符 '+' 的处理函数. ... 另有 '-', '*', '/' 等大量运算符. unaryfunc nb_negative; // 一元运算符 '-' 处理函数. ... 另有 '+', abs() 运算符等. ... 各种数学计算函数处理... }
函数族 PySequenceMethods, PyMappingMethods 类似. (我想可能虚函数太多, 如果都放 type 里面, 会导致
虚表太大; 当然要多一层间接访问, 以及要处理内存管理, 不是没有代价的...)
其实代码中还看到有 PyBufferProcs 是将此类 as_buffer 看待时的处理函数.
这样, PyTypeObject 可允许一种类型同时指定三种不同对象的行为特性.
类型对象也有自己的类型, 就是 PyType_Type (位于文件 Objects/typeobject.c 中). 在 python 中被称为
metaclass.
通过 PyObject 和 PyTypeObject, 相当于(但更灵活)实现了 C++ 的继承/多态.
从 PyObject* obj 中我们得到 obj->ob_type 就能够知道该对象的类型, 知道类型也即知道如何处理该对象.
例子: PyObject_Print() 的实现即是调用 obj->obj_type->tp_print(obj).
Python 的垃圾收集机制通过引用计数实现. 宏 Py_INCREF(op) Py_DECREF(op) 用于增减引用计数.
(这里未提及循环引用问题?)
Python 的类型对象不受引用计数规则限制, 永远不会被析构. (这样会引发问题).
Python 析构不一定立刻 free() 内存, 一般内部大量使用了内存池技术.
从概念上大致分为 5 类, 只是一种视角:
1. Fundamental 对象: 类型对象, type.
2. Numeric 对象: 数值对象, integer, float, boolean.
3. Sequence 对象: seq 序列集合对象, 如 string, list, tuple. (类似于 Array)
4. Mapping 对象: map 关联对象, 如 dict. (类似于 Hash)
5. Internal 对象: 虚拟机内部使用的对象, 如 function, code, frame, module, method.
OK, 以上是 Python 对象体系的基本认识. 以后可以分析别的部分了.