Python源码剖析[9] —— PyListObject对象(1)

    技术2022-05-11  70

    [绝对原创 转载请注明出处]

    Python源码剖析

    ——PyListObject对象(1)

    本文作者: Robert Chen (search.pythoner@gmail.com )

    1.      PyListObject对象

    元素的一个群是一个非常重要的抽象概念,我们可以将符合某一特性的一堆元素聚集为一个群,当然,还要可以向群中添加或删除元素。这样的群的概念对于编程语言十分重要,C语言就内建了数组的概念,随着编程语言的发展,现在所有的编程语言都会在语言中或标准库中实现这样的群的概念。而且群的概念还进一步地细分为多种实现方式,比如mapvector等。每一种实现都为某种目的的元素聚集或元素访问提供了极大的方便。

    PyListObjectPython提供的对列表的抽象,熟悉C++的人可能会条件反射地将PyListObjectC++中的list对应起来(至少它们名字是相同的:)。而实际上,Python中的列表和C++STL中的vector更为相似。

    PyListObject对象可以有效地支持插入,添加,删除等操作,在Python的列表中,无一例外地存放的都是PyObject的指针。所以实际上,你可以这样看待Python中的列表:vector<PyObject*>

    很显然,PyListObject一定是一个变长对象,因为不同的list中存储的元素的个数会是不同的。但是,和PyStringObject不同的是,PyListObject对象还支持插入删除等操作,可以在运行时动态地调整其所维护的内存,所以,它还是一个可变对象。

    下面看一看PyListObject的声明:

    [listobject.h]

    typedef struct {

        PyObject_VAR_HEAD

        /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */

        PyObject **ob_item;

        int allocated;

    } PyListObject;

     

     

    如我们所想,在PyListObject的头,赫然是一个PyObject_VAR_HEAD,随后是一个PyObject**,这个指针正是维护了PyObject*列表的关键。我们知道在PyObject_VAR_HEAD中,有一个ob_size,而在PyListObject的最后,又有一个allocated,那么这两个变量之间的关系是什么呢?

    其实,ob_sizeallocated都和内存的管理有关,PyListObject所采用的内存管理策略和C++vector采取的内存分配策略是一样的。它并不是存了多少东西就申请对应大小的内存,这样的申请策略显然是低效的,因为我们有理由相信,用户选用列表正是为了频繁地插入删除元素。因此,PyListObject在每一次需要申请内存的时候,会申请一大块内存,这是申请的总内存的大小记录在allocated中,而这些内存中实际被有效的PyObject*占用的内存大小被记录在了ob_size中。那么不难得到,对于一个PyListObject对象,一定存在以下的关系:

    0 <= ob_size <= allocated

    len(list) == ob_size

    ob_item == NULL implies ob_size == allocated == 0

    这里ob_sizeallocated的关系就像C++vectorsizecapacity的关系一样。


    最新回复(0)