深入理解 Python 虚拟机:元组(tuple)的实现原理及源码剖析

科技资讯 投稿 7700 0 评论

深入理解 Python 虚拟机:元组(tuple)的实现原理及源码剖析

深入理解 Python 虚拟机:元组(tuple)的实现原理及源码剖析

元组的结构

在这一小节当中主要介绍在 python 当中元组的数据结构:

typedef struct {
    PyObject_VAR_HEAD
    PyObject *ob_item[1];

    /* ob_item contains space for 'ob_size' elements.
     * Items must normally not be NULL, except during construction when
     * the tuple is not yet visible outside the function that builds it.
     */
} PyTupleObject;

#define PyObject_VAR_HEAD      PyVarObject ob_base;
typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

从上面的数据结构来看和 list 的数据结构基本上差不多,最终的使用方法也差不多。将上面的结构体展开之后,PyTupleObject 的结构大致如下所示:

    Py_ssize_t,一个整型数据类型。

  • ob_type,表示这个对象的数据类型是什么,在 python 当中有时候需要对数据的数据类型进行判断比如 isinstance, type 这两个关键字就会使用到这个字段。

  • ob_item,这是一个指针,指向真正保存 python 对象数据的地址,大致的内存他们之间大致的内存布局如下所示:

元组操作函数源码剖析

创建元组

首先我们需要了解一下在 cpython 内部关于元组内存分配的问题,首先和 list 一样,在 cpython 当中对于分配的好的元组进行释放的时候,并不会直接进行释放,而是会先保存下来,当下次又有元组申请内存的时候,直接将这块内存进行返回即可。

static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
static int numfree[PyTuple_MAXSAVESIZE];
    free_list,保存指针——指向被释放的元组。
  • numfree,对应的下标表示元组当中元素的个数,numfree[i] 表示有 i 个元素的元组的个数。

下面是新建 tuple 对象的源程序:

PyObject *
PyTuple_New(Py_ssize_t size
{
    PyTupleObject *op;
    Py_ssize_t i;
    if (size < 0 {
        PyErr_BadInternalCall(;
        return NULL;
    }
#if PyTuple_MAXSAVESIZE > 0
    // 如果申请一个空的元组对象 当前的 free_list 当中是否存在空元组对象 如果存在则直接返回
    if (size == 0 && free_list[0] k
        op = free_list[0];
        Py_INCREF(op;
        return (PyObject * op;
    }
    // 如果元组的对象元素个数小于 20 而且对应的 free_list 当中还有余下的元组对象 则不需要进行内存申请直接返回
    if (size < PyTuple_MAXSAVESIZE && (op = free_list[size] != NULL {
        free_list[size] = (PyTupleObject * op->ob_item[0];
        numfree[size]--;
        /* Inline PyObject_InitVar */
        _Py_NewReference((PyObject *op; // _Py_NewReference 这个宏是将对象 op 的引用计数设置成 1
    }
    else
#endif
    {
        /* Check for overflow */
        // 如果元组的元素个数大或者等于 20 或者 当前 free_list 当中没有没有剩余的对象则需要进行内存申请
        if ((size_tsize > ((size_tPY_SSIZE_T_MAX - sizeof(PyTupleObject -
                    sizeof(PyObject * / sizeof(PyObject * {
          	// 如果元组长度大于某个值直接报内存错误
            return PyErr_NoMemory(;
        }
        // 申请元组大小的内存空间
        op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size;
        if (op == NULL
            return NULL;
    }
		// 初始化内存空间
    for (i=0; i < size; i++
        op->ob_item[i] = NULL;
#if PyTuple_MAXSAVESIZE > 0
    // 因为 size == 0 的元组不会进行修改操作 因此可以直接将这个申请到的对象放到 free_list 当中以备后续使用
    if (size == 0 {
        free_list[0] = op;
        ++numfree[0];
        Py_INCREF(op;      

编程笔记 » 深入理解 Python 虚拟机:元组(tuple)的实现原理及源码剖析

赞同 (40) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽