看书 Python 源码分析笔记 (一) 对象初探

从网络上下载《 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 中都是
通过 python 内的对象来实现的. 有内建类型对象, 如 int, string, dict.

Python 自 1989 年开始, 实现语言为 ANSI C.

在 Python 中, 对象是在 C 堆上分配的一块(连续)内存, 一般不是静态的, 也不在堆栈空间. 内建类型对象是静态
初始化的 一个例外. 对象一旦创建, 内存大小即不可变. (这里暗示 GC 不会移动对象)

Python 内的对象

对象机制的基石是 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.

Python 对象的多态性

通过 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() 内存, 一般内部大量使用了内存池技术.

 

Python 对象的分类

从概念上大致分为 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 对象体系的基本认识. 以后可以分析别的部分了.

你可能感兴趣的:(看书 Python 源码分析笔记 (一) 对象初探)