• Python源码分析:PyObject对象的起源与多态的实现


    在python中一切皆是对象,那么这种机制是如何实现的呢?下面就让我们从python的老巢“源码”来看看这个神秘的机制。

    typedef struct _object {

    PyObject_HEAD

     } PyObject;

     

    typedef struct {

    PyObject_VAR_HEAD

    } PyVarObject;

     

    看到上面这两个结构体了吗?它们就是万源之源,所有python对象的祖先,为什么有两个祖先呢?这就要从现实时间的数据对象谈起,我们有些数据,像数字、固定矩阵这类数据其元素个数是固定不变的,而像字符串、集合、字典这类数据其元素个数是会上下浮动的。这样python的发明者在设计python时就为这两类数据创造了两个祖先(像人有男人与女人一样,好像不太确切,但本质就是有两个祖先了):定长数据类型与变长数据类型。

    这两个结构体里面的两个变量,其实都是些宏。从源中我们可以找到这些宏的展开:

    #define PyObject_HEAD

    _PyObject_HEAD_EXTRA

    Py_ssize_t ob_refcnt;

     

    struct _typeobject *ob_type;

    #define PyObject_VAR_HEAD

    PyObject_HEAD

    Py_ssize_t ob_size;

    看得出来,类型多了的这个ob_size就说明了它的变长特性(元素的个数)。

    下面我们来仔细看看PyObject_HEAD这个宏的内容:

    _PyObject_HEAD_EXTRA:这个宏展开时要么是双向链表的前后指针要么是空,是在跟踪所有对象时使用:想像一下,一个双向链表把python所有的对象串联起来的场景,好宏大呀!

    ob_refcnt:这个属性记录该对象被他人引用的次数(后面发现,这个东西是用来进行内存管理的:引用计数式的垃圾回收机制)

    ob_type:这个玩意是个重头戏,它实现了python的多态(何谓多态:对于不同的类型的对象,相同名称的方法其表现行为不同),何以见得呢?下面就让我们重点分析下这个ob_type,首先看看ob_type的原型是什么:

    typedef struct _typeobject {

    PyObject_VAR_HEAD

    const char *tp_name;

    Py_ssize_t tp_basicsize, tp_itemsize;

    printfunc tp_print;

    。。。

     

    PyNumberMethods *tp_as_number;

    PySequenceMethods *tp_as_sequence;

    PyMappingMethods *tp_as_mapping;

    。。。

    } PyTypeObject;

    这个结构体在源代码中整整占了84行,天呢!它是个什么,这么多内容。我们重点看几个字段:

    PyObject_VAR_HEAD

    :嗯,这不是变长数据类型它老祖先里的头‘骨’吗?怎么这里还有呢?没错,你猜对了,我们指明某个对象类型的对象原型 PyTypeObject也是一个对象。至于为什么是变长类型的对象祖先的头’骨‘,还没搞清楚^0^。

    tp_print:多态的内部原理开始显露了吧!就是通过这个type对象来为具体不同的对象提供不同的方法实现,尽量方法名字都一样。

    PyNumberMethods,PySequenceMethods,PyMappingMethods:其实和上面这个tp_print一样,只不它们是个函数族(由函数集构成),类数字操作(比如支持+-×/)、类序列操作(比如[n:m]切片操作)、字典操作(比如dict[key]操作)。

    下面就int类型对象对上面这些原理进行验证:

    typedef struct {

    PyObject_HEAD

    long ob_ival;

    } PyIntObject;

    这就是我们的int类型对象,其头部呢?在python源中可以看出,用一系列宏来实现头部的初始化:

    #define PyObject_HEAD_INIT(type)

    _PyObject_EXTRA_INIT

    1, type,

    这里的type,从源码中看出,有一个PyType_Type类型,它就是那个描述类型的类型的对象。有点绕了,但是仔细理解下来,也没什么,无外乎:一个int数据,有一个专门描述int类型数据的类型对象,但是不光有int类型的类型对象还有string类型的类型对象。那么就需要有一个要对象来描述这些类型对象,这就是PyType_Type,也就是它可以测试一个对象是不是类型对象。

  • 相关阅读:
    [PHP] laravel框架注意bootstrap/cache
    [git] git拉取远程分支代码
    Prometheus监控系统(4)pushgateway及自定义脚本
    k8s 学习
    pxc /Galera Cluster详解
    Percona Monitoring and Management
    etcd获取所有key
    kubernetes Pod驱逐迁移drain用法
    kubernetes etcd数据管理
    办公环境下k8s网络互通方案
  • 原文地址:https://www.cnblogs.com/muyiblog/p/7675669.html
Copyright © 2020-2023  润新知