Python源码之list列表对象底层解析

本文深入探讨了Python list对象的内部结构PyListObject,包括它的变长特性、元素长度的维护、对象创建和内存管理。PyListObject通过PyObject_VAR_HEAD维护元素长度,用allocated记录可容纳元素数量,ob_size记录实际使用数量。PyListObject对象的创建通过PyList_New函数实现,利用缓冲池提高效率。插入和删除元素涉及内存调整和引用计数管理,插入操作的时间复杂度为O(N)。删除元素时,会进行元素比较和内存搬运。PyListObject对象销毁时,其元素列表内存会被释放,对象可能被添加回缓冲池。
摘要由CSDN通过智能技术生成


  在Python中我们使用地最多的容器应该就是list了,list具有非常强大的功能,它不仅拥有像Java等其他语言的数组一样通过下标索引来读取列表中元素的功能,而且又高于数组,因为它可以在容器中存储不同类型的数据。为什么列表会具有这么强大的功能呢?实际上,其底层就是一个数据结构中的线性表的顺序表结构,只不过,它并非简单的一体式存储,而是采用了分离式的顺序表结构,在后面的解析中我们会慢慢一步步揭开它的神秘面纱,那么当我们在利用列表容器来对一系列数据进行操作时,是否能够清楚地了解其底层做了哪些事情吗?接下来我们就来详细解析一下list的底层实现。

1、PyListObject对象

  在之前的文章中我提到过,Python中的对象分为定长对象和变长对象,而list就是一种变长对象,很显然我们需要存储的数据不像Python2中的整数对象那样在一开始就已经确定了其大小,列表的长度是变化的。不仅如此,它还是可变对象,这和之前我们说的字符串对象不一样。列表在进行插入或者删除操作时可动态调整其维护的内存和元素。老规矩,我们来看一看它的定义:

// listobject.h
typedef struct {
   
    PyObject_VAR_HEAD
    PyObject **ob_item;
    Py_ssize_t allocated;
} PyListObject;

  不错,从定义来看它确实是一个变长对象因为它具有PyObject_VAR_HEAD这个头部,这个宏拥有一个ob_size的变量,这个变量就是维护数据元素长度的,从之前的文章中我们应该很清楚了。ob_item是一个PyObject **类型的指针,这个指针指向了元素列表所在内存块的首地址。之前在解析字符串对象的时候我们知道其中有个变量ob_sval,它是一个长度为1的字符数组,它也指向字符串的第一个字符,同理,列表对象中的这个指针也是,list[0]实际上就是ob_item[0]. allocated这个变量是维护的列表中可容纳元素的长度。可能你会说PyObject_VAR_HEAD中的ob_size不也是维护的元素的长度吗?这不是多此一举吗?这是怎么回事?您先别急,且听我慢慢道来。
  实际上,ob_size和allocated都是维护元素列表长度的,它们都与对象的内存管理机制相关,您看到后面就慢慢清楚了。我们知道,内存频繁申请会影响到程序的执行效率,性能会变得比较低下,如果采用存多大的数据就申请多大的内存的管理方式,其效率太低。因此,在为其申请内存的时候,会先申请一块内存,用allocated记录其数量,而ob_size变量则用来记录使用了多少数量的内存。也就是说假如一个PyListObject对象可容纳10个元素,其中已经存入了5个元素,那么,allocated为10,ob_size则为5。我们在利用len()这个函数计算列表长度时,实际上就是取出ob_size的值直接返回。

2、PyListObject对象的创建和维护

  • 2.1 创建对象

  创建list对象是通过PyList_New这个函数来实现的,这个函数接收一个参数用于指定列表元素的个数:

// listobject.c
PyObject* PyList_New(int size)
{
   
	PyListObject* op;
	size_t nbytes;
	// 内存溢出检查
	nbytes = size * sizeof(PyObject *);
	if(nbytes / sizeof(PyObject *) != (size_t) size)
		return Py_Err_NoMemory();
	// 为PyListObject对象申请内存空间
	if (num_free_lists){
   
		// 缓冲池可用
		num_free_lists --;
		op = free_lists[num_freee_lists];
		_Py_New_Reference((PyObject *) op);
	} else {
   
	// 缓冲池不可用
	op = PyObject_GC_New(PyListObject, &PyList_Type);
	}
	// 为PyListObject维护的元素列表申请空间
	if (size <= 0)
		op->ob_item = NULL;
	else{
   
	op->ob_item = (object **) PyMem_MALLOC(nbytes);
	memset(op->ob_item, 0, nbytes);
	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值