在前文中,我们注意到PyObject的第二个成员*ob_type变量,他是一个PyTypeObject,同时我们也知道,PyTypeObject可以帮助PyObject*动态判断这个指针所指数据的类型。

那么PyTypeObject到底是起什么作用的呢?

PyTypeObject

PyTypeObject定义如下:

/* File: cpython/Include/object.h */
typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "<module>.<name>" */
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
    // ...
} PyTypeObject;

PyTypeObject其实存储了PyObject及其派生类的元信息,比如名字是什么、分配多少空间、一些op操作(比如print)应该如何输出、说明文档、迭代器、如何释放空间等等。

从类的定义代码中,我们可以看到TypeObject的成员主要有4类。

  • tp_name 名字信息,对应于<module>.<name>
  • tp_basicsize, tp_itemsize,对象分配内存的大小信息
  • 关联的 methods,比如print,as_number,hash,iterator等
  • 具体类型相关的类型信息

在PyObject创建过程中,会以相应的PyTypeObject初始化内部的ob_type*指针。

但是我们会注意到PyTypeObject其实也是一种PyObject。因此,一个PyTypeObject实例的第二个成员,也是一个指向PyTypeObject的指针。这个PyTypeObject指向了 PyType_Type实例,而PyTypeType实例的*obtype指针指向自己。读起来很绕,我们以PyFloatObject为例,用一张图说明。

PyFloat_Type的实例化在 floatobject.c 中实现, 可以看到初始化时传入了PyType_Type的地址,而类似的,PyType_Type在 typeobject.c中实现,初始化时传入的地址是他自己。

/* File: cpython/Object/floatobject.c */

PyTypeObject PyFloat_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "float",
    sizeof(PyFloatObject),
    0,
    // ...
};
/* File: cpython/Object/typeobject.c */
PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                                     /* tp_name */
    sizeof(PyHeapTypeObject),                   /* tp_basicsize */
    // ...
};

results matching ""

    No results matching ""