Python 对象机制基石
上图是Include/object.h
,也是整个 cPython 中的最重要的结构体和它们的关系。
note : 这个图并不是 UML 中的类图哦,只是用来表示这些结构体之间的关系,毕竟 c语言 中并没有什么对象。箭头表示 引用 或 依赖 关系。
PyObject 和PyVarObject
可以看到PyObject
只有两个字段(下面我们称名为Py{type}Object
的结构体为{type}对象
):
ob_refcnt
: 引用计数字段,众所周知,Python的垃圾回收机制主要就是引用计数,因此,这个字段是所有的对象都有的。ob_type
: 指明该对象是什么 类型 的,这里指向的是一个 Type对象 。
而PyVarObject
只比PyObject
多一个ob_size
字段,用来指明这个 Var(变长)对象 的长度。
不只是PyVarObject
, Python 中的所有对象都是对PyObject
的一个扩展。换句话说,在Python 内部,每一个对象都拥有相同的对象头部,这就使得对对象的引用变得非常的统一,我们只需要用一个 PyObject *
指针就可以引用任意一个对象,而不论该对象实际是什么对象。
用面向对象的角度看,就是说PyObject
是Python 中所有对象的基类。
类型对象 PyTypeObject
PyObject
中的ob_type
字段指向PyTypeObject
, 这个PyTypeObject
就是用来指明这个对象到底是用来干什么的,
这个结构体里包含一个初始化对象、分配内存大小的信息:tp_basicsize, tp_itemsize
, 和一堆函数指针表明该对象相应的操作。
就像:
In [1]: dir(type)
Out[1]:
['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__', '__delattr__', '__dict__', '__dictoffset__', '__dir__', '__doc__', '__eq__', '__flags__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__instancecheck__', '__itemsize__', '__le__', '__lt__', '__module__', '__mro__', '__name__', '__ne__', '__new__', '__prepare__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasscheck__', '__subclasses__', '__subclasshook__', '__text_signature__', '__weakrefoffset__', 'mro']
不出意外,这个PyTypeObject
也是一个对象。所以这个 类型对象 也应该有它的 类型 ,这就是图上PyTypeObjecct
自己指向自己的原因: 类型对象 的 类型 是它自己(嗯,套娃了)。
就像:
In [2]: class A(object):
...: pass
...:
In [3]: A.__class__
Out[3]: type
In [4]: type.__class__
Out[4]: type
In [5]: int.__class__
Out[5]: type
对象的表现行为 Py{type}Methods
PyNumberMethods
,PySequenceMethods
,PyMappingMethods
这三个结构体就像面向对象里的接口 或者是重载操作符。例如,你为某个对象实现了PyNumberMethods
的nb_add
方法(其他方法默认),那么这个对象就能表现的像数值对象,尤其在遇到+
操作符时,就会调用你实现的nb_add
方法。
总结
上面就是Python 对象机制的结构,知道了上面这些,就可以去看Include
和 Objects
下的具体内建类型的代码了。这些内建类型代码遵循固定的结构:
- 在
Include/{type}object.h
下定义相应的Py{type}Object
。 - 在
Object/{type}object.c
下实现这个对象支持的操作,用这些函数初始化这个对象的类型对象, 和这个对象的表现行为。