zoukankan      html  css  js  c++  java
  • 《python源代码剖析》笔记 python中的List对象

    本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie


    1.PyListObject对象 --> 变长可变对象,可看作vector<PyObject *>

    typedef struct{
    	PyObject_VAR_HEAD //当中的ob_size表示实际被使用的内存的数量
    	PyObject **ob_item;//ob_item为指向元素列表的指针,实际上,Python中的list[0]就是ob_item[0]
    	int allocated;//当前列表中可容纳的元素的总数
    }
    PyList_Type 对象 --> PyListObject的类型对象
    typedef struct{
    	PyObject_VAR_HEAD //当中的ob_size表示实际被使用的内存的数量
    	PyObject **ob_item;//ob_item为指向元素列表的指针。实际上,Python中的list[0]就是ob_item[0]
    	int allocated;//当前列表中可容纳的元素的总数
    }
    2.创建PyListObject对象
    一种途径:
    PyObject *PyList_New(int size)
    1.内存数量计算,溢出检查
    2.为PyListObject对象申请空间
    3.为PyListObject对象中维护的元素列表申请空间

    PyListObject缓冲池,缓存的仅仅是PyListObject *
    #define MAXFREELISTS 80
    static PyListObject *free_lists[MAXFREELISTS]
    static int num_free_lists = 0;
    在第一个PyListObject创建的时候。num_free_lists是0,
    会调用 PyObject_GC_New在系统堆上创建一个新的PyListObject对象
    当一个PyListObject被销毁时,它会被缓存到PyListObject缓冲池中
    假设创建的不是第一个PyListObject时,会检查num_free_lists是否为0。
    假设不是的话,在缓冲池中的PyListObject对象会被又一次唤醒,又一次分配PyObject *
    元素列表占用内存,而num_free_lists也会对应的减一。

    设置元素
    int
    PyList_SetItem(register PyObject *op, register Py_ssize_t i,
                   register PyObject *newitem)
    {
        register PyObject *olditem;
        register PyObject **p;
        if (!PyList_Check(op)) {
            Py_XDECREF(newitem);
            PyErr_BadInternalCall();
            return -1;
        }
    	//[1]:索引检查
        if (i < 0 || i >= Py_SIZE(op)) {
            Py_XDECREF(newitem);
            PyErr_SetString(PyExc_IndexError,
                            "list assignment index out of range");
            return -1;
        }
    	//[2]:设置元素
        p = ((PyListObject *)op) -> ob_item + i;
        olditem = *p;
        *p = newitem;
        Py_XDECREF(olditem);//注意要将旧元素的引用减一。好让GC自己主动回收olditem所指向的内存
    						//用Py_XDECREF,而不用Py_DECREF是由于olditem有可能是NULL
        return 0;
    }
    插入元素

    static int
    ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
    {
        Py_ssize_t i, n = Py_SIZE(self);
        PyObject **items;
        if (v == NULL) {
            PyErr_BadInternalCall();
            return -1;
        }
        if (n == PY_SSIZE_T_MAX) {
            PyErr_SetString(PyExc_OverflowError,
                "cannot add more objects to list");
            return -1;
        }
    	//[1]:调整列表容量
        if (list_resize(self, n+1) == -1)
            return -1;
    	//[2]:确定插入点
        if (where < 0) {
            where += n;
            if (where < 0)
                where = 0;
        }
        if (where > n)
            where = n;
    	//[3]:插入元素
        items = self->ob_item;
        for (i = n; --i >= where; )
            items[i+1] = items[i];
        Py_INCREF(v); //由于多了一个指向v的指针。所以要添加v的引用数目
        items[where] = v;
        return 0;
    }
    
    
    int
    PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem)
    {
        if (!PyList_Check(op)) {
            PyErr_BadInternalCall();
            return -1;
        }
        return ins1((PyListObject *)op, where, newitem);
    }
    
    
    static int
    list_resize(PyListObject *self, Py_ssize_t newsize)
    {
        PyObject **items;
        size_t new_allocated;
        Py_ssize_t allocated = self->allocated;
    
    
    	//假设newsize < allocated && newsize > allocated/2。就不须要又一次申请内存
        if (allocated >= newsize && newsize >= (allocated >> 1)) {
            assert(self->ob_item != NULL || newsize == 0);
            Py_SIZE(self) = newsize;
            return 0;
        }
    
        new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
    
    
        /* check for integer overflow */
        //...
    	
        if (newsize == 0)
            new_allocated = 0;
    	//扩展列表
        items = self->ob_item;
        PyMem_RESIZE(items, PyObject *, new_allocated);//终于调用C中的realloc
        
        self->ob_item = items;
        Py_SIZE(self) = newsize;
        self->allocated = new_allocated;
        return 0;
    }



    删除元素
    比較操作
    int PyObject_RichCompareBool(PyObject *v, PyObject *w, int op)
    
    /* a[ilow:ihigh] = v if v != NULL.
     * del a[ilow:ihigh] if v == NULL.
     * 当v!=NULL时,用v替换a[ilow:ihigh]
     * 当v == NULL时,删除a[ilow:ihigh]
     */
    static int
    list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)





    3.PyListObject对象缓冲池
    static void list_dealloc(PyListObject *op)

    1.销毁PyListObject对象维护的元素列表。对list中的每个元素改变其引用计数。然后将内存释放
    2.释放PyListObject自身。查看缓存的PyListObject的数量是否已经满了,假设没有,就将该待删除的PyListObject
    对象放到缓冲池。以备后用。缓冲的不过PyListObject对象,而没有这个对象以前拥有的PyObject *元素列表

    4.Hack PyListObject

  • 相关阅读:
    MyBatis 学习记录3 MapperMethod类
    MyBatis 学习记录2 Mapper对象是如何生成的
    MyBatis 学习记录1 一个简单的demo
    hadoop学习记录1 初始hadoop
    Java枚举类的serialVersionUID
    docker学习记录1
    mysql utf8方式连接查看表数据乱码的问题
    在Spring中使用Redis Lua脚本批量删除缓存
    redis 批量删除键
    前后端分离跨域问题解决方案
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/7384028.html
Copyright © 2011-2022 走看看