在面向对象理论中,类(class)和对象(object)是非常重要的两个概念。在 Python 内部,二者都是对象。Python 由 C 语言实现,所以一个 Python 对象就是一个 C 结构体(struct)。不同对象有不同的数据和行为,但所有对象都共享一些共性 —— 比如引用计数(用于垃圾回收)。因此,所有对象结构体都共享一个公共头部。在 CPython 中,每个对象都由 PyObject 结构体表示,对象引用就是 PyObject* 指针。定义在 Include/object.h:
typedef struct _object { _PyObject_HEAD_EXTRA Py_ssize_t ob_refcnt; struct _typeobject *ob_type;} PyObject;
ob_refcnt引用计数,GC 核心;ob_type:指向类型对象的指针,决定对象是什么类型#ifdef Py_TRACE_REFS#define _PyObject_HEAD_EXTRA \ struct _object *_ob_next; \ struct _object *_ob_prev;#else#define _PyObject_HEAD_EXTRA#endif
PyVarObject:可变长度对象.对于列表、字符串这类长度可变的对象,需要在 PyObject 基础上增加长度字段:typedef struct { PyObject ob_base; Py_ssize_t ob_size; /* 元素数量 */} PyVarObject;
固定长度对象(PyObject):┌──────────────┐│ ob_refcnt │├──────────────┤│ ob_type │└──────────────┘可变长度对象(PyVarObject):┌──────────────┐│ ob_refcnt │├──────────────┤│ ob_type │├──────────────┤│ ob_size │ ← 元素个数└──────────────┘
真实对象结构体示例PyFloatObject(固定长度)浮点数是固定大小,只需要在头部后加一个 double:typedef struct { PyObject_HEAD double ob_fval;} PyFloatObject;
┌──────────────┐│ ob_refcnt │ = 1├──────────────┤│ ob_type │──▶ PyFloat_Type├──────────────┤│ ob_fval │ = 3.14└──────────────┘
PyListObject(可变长度)列表使用动态数组存储元素指针:typedef struct { PyObject_VAR_HEAD PyObject **ob_item; Py_ssize_t allocated;} PyListObject;
PyObject定义了对象公共字段,但创建对象时需要多少内存?对象支持哪些方法?这都在PyTypeObject中表示typedef struct _typeobject { PyObject_VAR_HEAD const char *tp_name; /* 类型名,如 "float" */ Py_ssize_t tp_basicsize; /* 实例内存大小 */ Py_ssize_t tp_itemsize; /* 可变类型元素大小 */ destructor tp_dealloc; /* 析构函数 */ printfunc tp_print; getattrfunc tp_getattr; setattrfunc tp_setattr; struct _typeobject *tp_base; /* 基类 */} PyTypeObject;
接下来我们看看类型对象和示例对象的内存关系,以float为例:>>> pi = 3.14>>> type(pi) is float # True
PyFloat_Type(唯一的类型对象)┌─────────────────────────────────────────────────┐│ ob_type → PyType_Type ││ tp_name = "float" ││ tp_basicsize = sizeof(PyFloatObject) │└─────────────────────────────────────────────────┘ ▲ ▲ │ ob_type │ ob_type┌─────────┴─────────┐ ┌─────────┴─────────┐│ pi=3.14 │ │ e=2.71 ││ ob_refcnt=1 │ │ ob_refcnt=1 ││ ob_fval=3.14 │ │ ob_fval=2.71 │└───────────────────┘ └───────────────────┘ (PyFloatObject) (PyFloatObject)
全局只存在 一个float 类型对象,但可以有无数个 float 实例。Python 中 object 是所有类的基类,对应 C 结构体PyTypeObject PyBaseObject_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "object", sizeof(PyObject), 0, object_dealloc, // ...};
解释器初始化时,PyType_Ready 会自动把所有类的基类指向它:if (base == NULL && type != &PyBaseObject_Type) { base = type->tp_base = &PyBaseObject_Type;}
┌─────────────────────────────────────────────────────────────┐│ 完整对象模型体系 ││ ││ 实例对象 类型对象 元类型/基类 ││ ││ ┌────────┐ ┌────────────┐ ││ │ 3.14 │───┐ │ PyFloat_Type│ ││ └────────┘ │ │ "float" │───tp_base───┐ ││ │ └────────────┘ │ ││ ┌────────┐ │ │ ││ │ [1,2,3]│───┼──▶│ PyList_Type │ │ ││ └────────┘ │ │ "list" │───tp_base───┤ ││ │ └────────────┘ │ ││ │ │ ││ │ ┌────────────┐ │ ││ └──▶│ PyType_Type│◀───────────┘ ││ │ "type" │───ob_type──▶(自己) ││ └────────────┘ │ ││ │ ││ ┌─────────────────────┐ │ ││ │ PyBaseObject_Type │◀──┘ ││ │ "object" │ ││ │ tp_base = NULL │ ││ └─────────────────────┘ │└─────────────────────────────────────────────────────────────┘