好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Python源码学习之PyType_Type和PyBaseObject_Type详解

PyType_Type和PyBaseObject_Type

PyObject和PyTypeObject内容的最后指出下图中对 实例对象 和 类型对象 的理解是不完全正确的,

浮点 类型对象全局唯一 ,python在C语言层面实现过程中将其定义为一个全局静态变量 ,定义于 Object/floatobject.c 中,命名为 PyFloat_Type 。

PyTypeObject PyFloat_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "float",
    sizeof(PyFloatObject),
    0,
    (destructor)float_dealloc,                  /* tp_dealloc */

    // ...
    (reprfunc)float_repr,                       /* tp_repr */

    // ...
};
gpWRnsyx 第2行使用初始化 ob_refcnt 、 ob_type 以及 ob_size 三个字段, PyVarObject_HEAD_INIT 的定义可以参考博文1.4.3节的内容。 第3行将 tp_name 字段初始化成类型名称"float" 再往下是各种操作的函数指针

ob_type 指针指向 PyType_Type ,这也是一个静态定义的全局变量。代表“类型的类型” 的type对象就是 PyType_Type 。

一. 类型的类型—PyType_Tpye(type的实体)

上文中,float类型对象在底层实现过程中对应 PyFloat_Type 全局静态变量。Python类型是一种对象,也有自己的类型,即Python中的type。

>>> float.__class__
<cHdhCmsTestcppcns测试数据lass 'type'>

自定义类型也遵循同样的规则,

>& 编程客栈 gt;> class Foo(object):
...     pass
...
>>> Foo.__class__
<class 'type'>

在查看 PyFloat_Type 代码实现时, ob_type 字段指向的 PyType_Type 就是type的实现。在 Object/typeobject.c 中定义,

PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                                     /* tp_name */
    sizeof(PyHeapTypeObject),                   /* tp_basicsize */
    sizeof(PyMemberDef),                        /* tp_ite gpWRnsyx msize */
    (destructor)type_dealloc,                   /* tp_dealloc */

    // ...
    (reprfunc)type_repr,                        /* tp_repr */

    // ...
};
内建类型和自定义类的 PyTypeObject 对象都是通过 PyType_Type 创建 。 PyType_Type 是 PyTypeObject 的一个实例。 PyType_Type 是类型机制中至关重要的对象, 是所有类型的类型 ,称为 元类型 。 第2行代码处 PyType_Type 将自身的 ob_type 字段指向它自己。
>>> type.__class__
<class 'type'>
>>> type.__class__ is type
True

由此,以float为例,可以绘制一个更完善但是并不完全正确的实例对象和类型对象在内存中的关系图,

二. 类型之基—PyBaseObject_Type(object的实体)

上一节中红色标记的语句,并不完全正确是因为思考过程中忽略了 object 对象的存在。

object 是另一个特殊的类型,是所有类型的基类。同样可以通过 PyFloat_Type 中 tp_base 字段顺藤摸瓜找到。然而,在源码的第2行的PyVarObject_HEAD_INIT定义中,该字段并没有初始化,

0,                                          /* tp_base */

更进一步查找代码中 PyFloat_Type 出现的地方,在 Object/object.c 中发现如下代码,

if (PyType_Ready(&PyFloat_Type) < 0)
    Py_FatalError("Can't initialize float type");

创建类型对象过程中,需要 PyType_Ready 方法将 tp_base 字段初始化,具体如下

int
PyType_Ready(PyTypeObject *type)
{
    // ...

    base = type->tp_base;
    if (base == NULL && type != &PyBaseObject_Type) {
        base = type->tp_base = &PyBaseObject_Type;
        Py_INCREF(base);
    }

    // ...
}

PyFloat_Type 中的 tp_base 字段初始化成 PyBaseObject_Type ,它就是object背后的实体,其源码定义为,

PyTypeObject PyBaseObject_Type = {
    PyVarObject_HEAD_INIT(&PyTyhttp://HdhCmsTestcppcns测试数据pe_Type, 0)
    "object",                                   /* tp_name */
    sizeof(PyObject),                           /* tp_basicsize */
    0,                                          /* tp_itemsize */
    object_dealloc,                             /* tp_dealloc */

    // ...
    object_repr,                                /* tp_repr */
};

源码中 ob_type 字段指向 PyType_Type 这与下方object在 Python中的测试代码相吻合,

>>> object.__class__
<class 'type'>

此外, PyType_Ready 函数初始化 PyBaseObject_Type 时,不设置 tp_base 字段。 因为继承链必须有一个终点,否则沿着继承链查找时会陷入死循环。

>>> print(object.__base__)
None

由此,得到了实例对象和类型对象在内存中完整的关系图。以float为例,

到此这篇关于Python源码学习之PyType_Type和PyBaseObject_Type详解的文章就介绍到这了,更多相关PyType_Type和PyBaseObject_Type内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

查看更多关于Python源码学习之PyType_Type和PyBaseObject_Type详解的详细内容...

  阅读:25次