python源码分析----对象结构

本文探讨了Python中的对象结构,指出所有内容都是对象,包括整数和方法。核心结构是PyObject,包含前后指针、引用计数和类型对象。Python的内存管理依赖于引用计数和可达性分析的垃圾收集器。PyVarObject是用于变长对象的结构,扩展了对象大小字段。类型对象同样是一个对象,有自己的类型对象,最顶层的类型对象PyType_Type形成自我引用,构成了Python类型的层次结构。
摘要由CSDN通过智能技术生成

虽然自己会吐槽python这语言让人受不了的慢,不过也不得不说python语言在语法上的精炼,在写代码的时候确实会比java方便一些。。。不过由于python无法像java一样项目的开始先定义一套强类型限制的接口,所以总感觉在写python的时候有点不踏实。。。不过pycharm从某种程度上通过注释也能减轻一点这方面的担忧。。

好了。。。。。决定了要看一下python的实现。。。这里就先从python的对象结构来说吧。。。。


在python中,所有的东西都是对象,整数是,方法也是,。。总之什么都是。。。。

在看python的代码实现中,可以随处看到指针类型:PyObject*,那么我们就先来看看PyObject这到底是怎么定义的吧:

typedef struct _object {  //这个是所有python对象的基础,这个是不可变对象
    PyObject_HEAD
} PyObject;

他就是整个python环境中最上层的对象结构,很简单,就包括一个对象头部,那么来看看它的定义:

//通过这个结构,将所有对象构成一个双链表
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;

#define _PyObject_EXTRA_INIT 0, 0,

#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif


//所有对象共有的数据,这个放在所有对象内存的最开始部分,首先是构成对象链表的前后执指针,其次是引用数量,以及它的类型对象
/**
 (1)前后指针,构成循环链表
 (2)引用计数
 (3)类型对象
**/
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD                   \
    _PyObject_HEAD_EXTRA                \
    Py_ssize_t ob_refcnt;               \
    struct _typeobject *ob_type;


可以看出,头部由3部分来构成,首先是一个前后指针,用于将对象构成一个双向的链表,其次就是比较重要的引用计数了。。。然后还有就是类型对象----》每一个对象都有一个指针指向其所指向的类型对象。。。


既然看到了引用计数,那么就来说说python的GC吧。。。它跟java在GC最大的不同点就是有一套基于引用计数的内存回收。。。

(1)每一个对象都关联一个引用计数,当这个计数为0的时候,那么它的内存就可以被回收了

(2)对于有循环引用的情况,python也有一套可达性分析的gc来回收内存。。当然它这部分就比java简单的多了


上面看的时最基础的PyObject结构。。。另外这里还有另外一种结构:PyVarObject,它用于指代一些变长对象,主要是一些容器。。。。

//一般都是一些容器啥的
typedef struct {        //可变对象的基础
    PyObject_VAR_HEAD
} PyVarObject;

 //即使是可变对象,首先也是有一个统一的对象头部,ob_size一般用于记录容器中数据项个数,注意这里不是字节数
#define PyObject_VAR_HEAD               \
    PyObject_HEAD                       \
    Py_ssize_t ob_size; /* Number of items in variable part */
#define Py_INVALID_SIZE (Py_ssize_t)-1

它其实也就是扩展了一个0b_size字段。。。本质上也是与PyObject统一的。。。。所以对于PyVarObject,也可以用PyObject指针来引用。。从而达到了统一。。。。


通过上面的内容,我们知道,所有的对象,都会有一个ob_type指针域,用于指向当前对象的类型对象,那么接下来来看看类型对象的定义:

//这个用来指定一个对象的类型对象
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 */   //用于分配的大小

    /* Methods to implement standard operations */
    //下面是标准方法的定义
    destructor tp_dealloc;    //析构当前对象
    printfunc tp_print;       //在调用print打印类型的时候,将会调用这里来进行输出
    getattrfunc tp_getattr;   //getter函数
    setattrfunc tp_setattr;   //setter函数
    cmpfunc tp_compare;       //比较函数
    reprfunc tp_repr;         //转化为字符串

    /* Method suites for standard classes */

    PyNumberMethods *tp_as_number;      //最为数字的进行操作的函数
    PySequenceMethods *tp_as_sequence;  //作为序列进行操作的函数
    PyMappingMethods *tp_as_mapping;    //作为字典进行操作的函数

    /* More standard operations (here for binary compatibility) */

    hashfunc tp_hash;                   //获取hash值的函数
    ternaryfunc tp_call;                //作为方法进行调用的时候
    reprfunc tp_str;
    getattrofunc tp_getattro;
    setattrofunc tp_setattro;

    /* Functions to access object as input/output buffer */
    PyBufferProcs *tp_as_buffer;       //将当前对象作为buffer进行处理的时候的方法

    /* Flags to define presence of optional/expanded features */
    long tp_flags;

    const char *tp_doc; /* Documentation string */   //当前类型的文档

    /* Assigned meaning in release 2.0 */
    /* call function for all accessible objects */
    traverseproc tp_traverse;

    /* delete references to contained objects */
    inquiry tp_clear;                            

    /* Assigned meaning in release 2.1 */
    /* rich comparisons */
    richcmpfunc tp_richcompare;

    /* weak reference enabler */
    Py_ssize_t tp_weaklistoffset;

    /* Added in release 2.2 */
    /* Iterators */
    getiterfunc tp_iter;
    iternextfunc tp_iternext;

    /* Attribute descriptor and subclassing stuff */
    struct PyMethodDef *tp_methods;          //方法
    struct PyMemberDef *tp_members;          //成员属性
    struct PyGetSetDef *tp_getset;
    struct _typeobject *tp_base;             //父类型
    PyObject *tp_dict;
    descrgetfunc tp_descr_get;
    descrsetfunc tp_descr_set;
    Py_ssize_t tp_dictoffset;
    initproc tp_init;
    allocfunc tp_alloc;
    newfunc tp_new;
    freefunc tp_free; /* Low-level free-memory routine */
    inquiry tp_is_gc; /* For PyObject_IS_GC */
    PyObject *tp_bases;
    PyObject *tp_mro; /* method resolution order */
    PyObject *tp_cache;
    PyObject *tp_subclasses;
    PyObject *tp_weaklist;
    destructor tp_del;

    /* Type attribute cache version tag. Added in version 2.6 */
    unsigned int tp_version_tag;

#ifdef COUNT_ALLOCS
    /* these must be last and never explicitly initialized */
    Py_ssize_t tp_allocs;
    Py_ssize_t tp_frees;
    Py_ssize_t tp_maxalloc;
    struct _typeobject *tp_prev;
    struct _typeobject *tp_next;
#endif
} PyTypeObject;

可以看到,这里主要是定义了很多公共的函数。。。。同时这里可以看到最开始他也定义了一个变长对象的头部PyObject_VAR_HEAD


那么也就是说,类型对象本身也是一个对象,也可以用PyObject指针来引用。。。。


嗯。。那么。。这里问题就来了。。。。既然类型对象也是一个对象。。。。那么类型对象他自己的类型对象是啥呢。。。?

嗯。。。在python中定义了一个最顶层的类型对象。。。。。

//最顶层的类型对象,它进行一个类型对象的自引用
PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                                     /* tp_name */
    sizeof(PyHeapTypeObject),                   /* tp_basicsize */
    sizeof(PyMemberDef),                        /* tp_itemsize */
    (destructor)type_dealloc,                   /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                  /* tp_compare */
    (reprfunc)type_repr,                        /* tp_repr */
    0,                                          /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    (hashfunc)_Py_HashPointer,                  /* tp_hash */
    (ternaryfunc)type_call,                     /* tp_call */
    0,                                          /* tp_str */
    (getattrofunc)type_getattro,                /* tp_getattro */
    (setattrofunc)type_setattro,                /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS,         /* tp_flags */
    type_doc,                                   /* tp_doc */
    (traverseproc)type_traverse,                /* tp_traverse */
    (inquiry)type_clear,                        /* tp_clear */
    type_richcompare,                                           /* tp_richcompare */
    offsetof(PyTypeObject, tp_weaklist),        /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    type_methods,                               /* tp_methods */
    type_members,                               /* tp_members */
    type_getsets,                               /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
    0,                                          /* tp_descr_get */
    0,                                          /* tp_descr_set */
    offsetof(PyTypeObject, tp_dict),            /* tp_dictoffset */
    type_init,                                  /* tp_init */
    0,                                          /* tp_alloc */
    type_new,                                   /* tp_new */
    PyObject_GC_Del,                            /* tp_free */
    (inquiry)type_is_gc,                        /* tp_is_gc */
};

这里可以看到它的类型对象本身引用了自己。。。。。

以后可以看到,所有的python类型对象都将它自己的类型对象指向了PyType_Type


好了。。基本上比较粗略的了解了python的对象结构。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值