精华内容
下载资源
问答
  • Python3.5源码分析-List概述

    千次阅读 2018-08-18 11:28:09
    Python3源码分析 本文环境python3.5.2。 参考书籍<<Python源码剖析>> python官网 Python3的List对象 list对象是一个变长对象,在运行时动态调整其所维护的内存和元素,并且支持...

    Python3源码分析

    本文环境python3.5.2。
    参考书籍<<Python源码剖析>>
    python官网
    

    Python3的List对象

    list对象是一个变长对象,在运行时动态调整其所维护的内存和元素,并且支持插入删除等操作,list的定义如下;

    #define PyObject_VAR_HEAD      PyVarObject ob_base;
    #define Py_INVALID_SIZE (Py_ssize_t)-1
    
    /* Nothing is actually declared to be a PyObject, but every pointer to
     * a Python object can be cast to a PyObject*.  This is inheritance built
     * by hand.  Similarly every pointer to a variable-size Python object can,
     * in addition, be cast to PyVarObject*.
     */
    typedef struct _object {
        _PyObject_HEAD_EXTRA
        Py_ssize_t ob_refcnt;                                       // 引用计数值
        struct _typeobject *ob_type;                                // 基本的类型 type
    } PyObject;
    
    typedef struct {
        PyObject ob_base;                                           // 对象基本信息
        Py_ssize_t ob_size; /* Number of items in variable part */  // 变长对象的元素个数
    } PyVarObject;
    ...
    typedef struct {
        PyObject_VAR_HEAD                                           // 变量头部信息
        /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
        PyObject **ob_item;                                         // 元素指向具体指
    
        /* ob_item contains space for 'allocated' elements.  The number
         * currently in use is ob_size.
         * Invariants:
         *     0 <= ob_size <= allocated
         *     len(list) == ob_size
         *     ob_item == NULL implies ob_size == allocated == 0
         * list.sort() temporarily sets allocated to -1 to detect mutations.
         *
         * Items must normally not be NULL, except during construction when
         * the list is not yet visible outside the function that builds it.
         */
        Py_ssize_t allocated;                                       // 当前空间
    } PyListObject;
    

    其中,ob_size就是list实际拥有的元素数量,allocated指的是实际申请的内存空间,比如列表A实际申请了5元素的空间,但是此时A只包含了2个元素,则ob_size为2,allocated为5。

    List的创建和初始化

    在新建List的时候会调用BUILD_LIST指令新建List,BUILD_LIST对应的字节码指令是,

        TARGET(BUILD_LIST) {
            PyObject *list =  PyList_New(oparg);        // 生成新的列表调用,传入初始化时传入的参数值
            if (list == NULL)
                goto error;
            while (--oparg >= 0) {
                PyObject *item = POP();
                PyList_SET_ITEM(list, oparg, item);     // 将初始化的列表值设置到列表中
            }
            PUSH(list);                                 // 压入list
            DISPATCH();                                 // 执行下一条指令
        }
    

    此时查看PyList_New函数,

    PyObject *
    PyList_New(Py_ssize_t size)
    {
        PyListObject *op;
        size_t nbytes;
    #ifdef SHOW_ALLOC_COUNT
        static int initialized = 0;
        if (!initialized) {
            Py_AtExit(show_alloc);
            initialized = 1;
        }
    #endif
    
        if (size < 0) {                                             // 如果传入的大小小于0则报错
            PyErr_BadInternalCall();
            return NULL;
        }
        /* Check for overflow without an actual overflow,
         *  which can cause compiler to optimise out */
        if ((size_t)size > PY_SIZE_MAX / sizeof(PyObject *))        // 计算申请的大小是否超过数组最大的索引值,PY_SIZE_MAX如果是64位则是最大的有符号int64值
            return PyErr_NoMemory();
        nbytes = size * sizeof(PyObject *);                         // 需要申请的内存字节大小
        if (numfree) {                                              // 缓冲池可用
            numfree--;
            op = free_list[numfree];                                // 获取缓冲的对象
            _Py_NewReference((PyObject *)op);
    #ifdef SHOW_ALLOC_COUNT
            count_reuse++;
    #endif
        } else {
            op = PyObject_GC_New(PyListObject, &PyList_Type);       // 生成新的对象
            if (op == NULL)
                return NULL;
    #ifdef SHOW_ALLOC_COUNT
            count_alloc++;
    #endif
        }
        if (size <= 0)                                              // 传入小于等于0
            op->ob_item = NULL;                                     // 则list实例的ob_item为NULL
        else {
            op->ob_item = (PyObject **) PyMem_MALLOC(nbytes);       // 申请nbytes字节大小的内存,并将申请内存的首地址设置到ob_item
            if (op->ob_item == NULL) {                              // 如果为空则报错
                Py_DECREF(op);
                return PyErr_NoMemory();
            }
            memset(op->ob_item, 0, nbytes);                         // 将对应nbytes字节的数据设置为0
        }
        Py_SIZE(op) = size;                                         // 设置ob->size 为size
        op->allocated = size;                                       // 设置allocated值
        _PyObject_GC_TRACK(op);                                     // 加入GC列表
        return (PyObject *) op;
    }
    

    在生成新的list的时候会先检查缓冲池是否拥有,默认会维护80个PyListObject对象;

    #ifndef PyList_MAXFREELIST
    #define PyList_MAXFREELIST 80
    #endif
    static PyListObject *free_list[PyList_MAXFREELIST];
    static int numfree = 0;
    

    在调用list_dealloc函数释放列表对象时,会检查缓冲池是否已经满了,如果没有满则添加到缓冲池中,

    static void
    list_dealloc(PyListObject *op)
    {
        Py_ssize_t i;
        PyObject_GC_UnTrack(op);
        Py_TRASHCAN_SAFE_BEGIN(op)
        if (op->ob_item != NULL) {
            /* Do it backwards, for Christian Tismer.
               There's a simple test case where somehow this reduces
               thrashing when a *very* large list is created and
               immediately deleted. */
            i = Py_SIZE(op);
            while (--i >= 0) {
                Py_XDECREF(op->ob_item[i]);                         // 减少列表对象的引用计数
            }
            PyMem_FREE(op->ob_item);                                // 释放ob_item申请的内存空间
        }
        if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))  // 如果缓冲池未满
            free_list[numfree++] = op;                              // 添加到缓冲池列表中
        else
            Py_TYPE(op)->tp_free((PyObject *)op);                   // 大于缓冲池大小则直接释放内存
        Py_TRASHCAN_SAFE_END(op)
    }
    

    当缓冲池没有可用list的时候,则新生成一个list,调用PyObject_GC_New(PyListObject, &PyList_Type)生成一个;

    #define PyObject_GC_New(type, typeobj) \
                    ( (type *) _PyObject_GC_New(typeobj) )      // 调用_PyObject_GC_New生成
    
    ...
    
    
    PyObject *
    _PyObject_GC_New(PyTypeObject *tp)
    {
        PyObject *op = _PyObject_GC_Malloc(_PyObject_SIZE(tp));     // 申请内存空间
        if (op != NULL)
            op = PyObject_INIT(op, tp);                             // 初始化op
        return op;                                                  // 返回
    }
    ...
    #define PyObject_INIT(op, typeobj) \
        ( Py_TYPE(op) = (typeobj), _Py_NewReference((PyObject *)(op)), (op) )    // 设置ob_type,增加引用计数
    
    ...
    
    #define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)    // 设置ob_type类型
    

    此时新生成的list对象就基本初始化完成。

    当调用给list设值时,会尝试如下字节码;

     14           0 LOAD_CONST               0 (1)
                  3 LOAD_CONST               1 (2)
                  6 BUILD_LIST               2
                  9 STORE_NAME               0 (a)
    
     15          12 LOAD_CONST               2 (10)
                 15 LOAD_NAME                0 (a)
                 18 LOAD_CONST               0 (1)
                 21 STORE_SUBSCR
    

    其中,a初始化为包含1,2两个元素的列表,然后设置a[1]=10,此时调用STORE_SUBSCR来设置,

        TARGET(STORE_SUBSCR) {
            PyObject *sub = TOP();                      // 获取需要设置的key
            PyObject *container = SECOND();             // 获取list实例
            PyObject *v = THIRD();                      // 获取待设置的值
            int err;
            STACKADJ(-3);                               // 栈移动三个值
            /* v[w] = u */
            err = PyObject_SetItem(container, sub, v);  // 设置值
            Py_DECREF(v);
            Py_DECREF(container);
            Py_DECREF(sub);
            if (err != 0)
                goto error;
            DISPATCH();
        }
    

    此时调用了PyObject_SetItem函数来将值设置到列表中,

    int
    PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value)
    {
        PyMappingMethods *m;
    
        if (o == NULL || key == NULL || value == NULL) {                    // 检查传入参数
            null_error();
            return -1;
        }
        m = o->ob_type->tp_as_mapping;                                      // 获取类型的tp_as_mapping方法
        if (m && m->mp_ass_subscript)
            return m->mp_ass_subscript(o, key, value);                      // 调用字典的设置方法
    
        if (o->ob_type->tp_as_sequence) {                                   // 调用tp_as_sequence方法
            if (PyIndex_Check(key)) {                                       // 检查key
                Py_ssize_t key_value;
                key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
                if (key_value == -1 && PyErr_Occurred())
                    return -1;
                return PySequence_SetItem(o, key_value, value);             // 调用设置值
            }
            else if (o->ob_type->tp_as_sequence->sq_ass_item) {
                type_error("sequence index must be "
                           "integer, not '%.200s'", key);
                return -1;
            }
        }
    
        type_error("'%.200s' object does not support item assignment", o);
        return -1;
    }
    

    由于此时,传入的list对象,此时的PyList_Type对应的tp_as_mapping为list_as_mapping;

    static PyMappingMethods list_as_mapping = {
        (lenfunc)list_length,
        (binaryfunc)list_subscript,
        (objobjargproc)list_ass_subscript
    };
    

    此时就是调用了list_ass_subscript方法来处理设值,

    static int
    list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
    {
        if (PyIndex_Check(item)) {                                          // item索引值检查
            Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);      // 检查值是否合法,不合法返回PyExc_IndexError
            if (i == -1 && PyErr_Occurred())                                // 如果检查不合法则返回错误
                return -1;
            if (i < 0)                                                      // 如果小于0, 则转换成正值索引
                i += PyList_GET_SIZE(self);
            return list_ass_item(self, i, value);                           // 设值值
        }
        ...
    }
    

    此时先检查索引值是否合法,然后将负值索引转换成正值索引,然后调用list_ass_item处理;

    static int
    list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v)
    {
        PyObject *old_value;
        if (i < 0 || i >= Py_SIZE(a)) {                             // 检查索引值是否超出范围
            PyErr_SetString(PyExc_IndexError,
                            "list assignment index out of range");       
            return -1;
        }
        if (v == NULL)
            return list_ass_slice(a, i, i+1, v);                    // 如果v为NULL则删除对应i索引处的值
        Py_INCREF(v);
        old_value = a->ob_item[i];                                  // 获取旧值
        a->ob_item[i] = v;                                          // 设值新值
        Py_DECREF(old_value);
        return 0;
    }
    

    至此一个List的设置过程就完成了。

    List的添加和删除元素

    a本来是[1,2]的列表,调用a.insert(5,105)时,对应的字节码如下;

     18          45 LOAD_NAME                0 (a)
                 48 LOAD_ATTR                3 (insert)
                 51 LOAD_CONST               3 (5)
                 54 LOAD_CONST               4 (105)
                 57 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
    

    此时就会调用listinsert函数,

    static PyObject *
    listinsert(PyListObject *self, PyObject *args)
    {
        Py_ssize_t i;
        PyObject *v;
        if (!PyArg_ParseTuple(args, "nO:insert", &i, &v))           // 解析参数和列表
            return NULL;
        if (ins1(self, i, v) == 0)                                  // 插入数据
            Py_RETURN_NONE;
        return NULL;
    }
    

    此时解析了相关参数为tuple后调用ins1插入数据,

    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;
        }
    
        if (list_resize(self, n+1) == -1)               // 重新扩招self大小
            return -1;
    
        if (where < 0) {                                // 如果索引为负值,则转换成正值
            where += n;                                 // 计算出正值索引
            if (where < 0)
                where = 0;                              // 如果转换后还是负值则置0
        }
        if (where > n)                              
            where = n;                                  // 如果where大于最大值则置为最大值n
        items = self->ob_item;
        for (i = n; --i >= where; )                     // 将大于where索引值的元素移动后一位
            items[i+1] = items[i]; 
        Py_INCREF(v);   
        items[where] = v;                               // 设置where为传入的v
        return 0;
    }
    

    首先会调整列表的大小,调用list_resize函数,

    static int
    list_resize(PyListObject *self, Py_ssize_t newsize)
    {
        PyObject **items;
        size_t new_allocated;
        Py_ssize_t allocated = self->allocated;                     // 获取当前的申请内存的大小
    
        /* Bypass realloc() when a previous overallocation is large enough
           to accommodate the newsize.  If the newsize falls lower than half
           the allocated size, then proceed with the realloc() to shrink the list.
        */ 
        if (allocated >= newsize && newsize >= (allocated >> 1)) {  // 如果已经申请的大小大于newsize并且newsize>=已有空间的一半
            assert(self->ob_item != NULL || newsize == 0);
            Py_SIZE(self) = newsize;                                // 设置ob_size为newsize
            return 0;
        }
    
        /* This over-allocates proportional to the list size, making room
         * for additional growth.  The over-allocation is mild, but is
         * enough to give linear-time amortized behavior over a long
         * sequence of appends() in the presence of a poorly-performing
         * system realloc().
         * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
         */
        new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);     // 否则就调整申请空间大小
    
        /* check for integer overflow */
        if (new_allocated > PY_SIZE_MAX - newsize) {                // 如果新申请的大小最大的大小
            PyErr_NoMemory();                                       // 则报错
            return -1;
        } else {
            new_allocated += newsize;                               // 新增newsize
        }
    
        if (newsize == 0)
            new_allocated = 0;
        items = self->ob_item;
        if (new_allocated <= (PY_SIZE_MAX / sizeof(PyObject *)))    // 检查新申请的大小是否在允许范围内
            PyMem_RESIZE(items, PyObject *, new_allocated);         // 重新调整ob_item的申请空间
        else
            items = NULL;
        if (items == NULL) {
            PyErr_NoMemory();
            return -1;
        }
        self->ob_item = items;                                      // 重置item
        Py_SIZE(self) = newsize;                                    // 重置size 为newsize
        self->allocated = new_allocated;                            // 重置申请的空间大小
        return 0;
    }
    

    在调整过列表大小后,列表会判断如果传入的负值索引比列表元素还大则设置在0位,如果转换的正值索引比列表长度还大则设置为最后一位,并将大于索引值的元素,往后移动一位。此时就是list的插入过程。

    当列表a=[1,2,10,105],调用a.remove(10)时,对应的字节码如下;

     20          71 LOAD_NAME                0 (a)
                 74 LOAD_ATTR                4 (remove)
                 77 LOAD_CONST               2 (10)
                 80 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                 83 POP_TOP
    

    此时调用了list的remove属性,对应调用了listremove方法,

    static PyObject *
    listremove(PyListObject *self, PyObject *v)
    {
        Py_ssize_t i;
    
        for (i = 0; i < Py_SIZE(self); i++) {                       // 循环遍历lise
            int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);     // 比较列表中的值与传入值v进行比较
            if (cmp > 0) {                                          // 如果找到
                if (list_ass_slice(self, i, i+1,
                                   (PyObject *)NULL) == 0)          // 设置该位为NULL
                    Py_RETURN_NONE;
                return NULL;
            }
            else if (cmp < 0)                                       
                return NULL;
        }
        PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list");     // 如果没有找到则返回该错误
        return NULL;
    }
    

    其中调用了PyObject_RichCompareBool函数,进行比较;

    int
    PyObject_RichCompareBool(PyObject *v, PyObject *w, int op)
    {
        PyObject *res;
        int ok;
    
        /* Quick result when objects are the same.
           Guarantees that identity implies equality. */
        if (v == w) {                               // 快速检查,如果两个相同则返回
            if (op == Py_EQ)
                return 1;
            else if (op == Py_NE)
                return 0;
        }
    
        res = PyObject_RichCompare(v, w, op);       // 比较v,w
        if (res == NULL)
            return -1;
        if (PyBool_Check(res))
            ok = (res == Py_True);
        else
            ok = PyObject_IsTrue(res);
        Py_DECREF(res);
        return ok;                                  // 返回结果
    }
    

    继续调用了PyObject_RichCompare函数进行比较,

    PyObject *
    PyObject_RichCompare(PyObject *v, PyObject *w, int op)
    {
        ...
        res = do_richcompare(v, w, op);                     // 进行比较
        ...
    }
    

    查看do_richcompare函数比较可知,

    /* Perform a rich comparison, raising TypeError when the requested comparison
       operator is not supported. */
    static PyObject *
    do_richcompare(PyObject *v, PyObject *w, int op)
    {
        richcmpfunc f;
        PyObject *res;
        int checked_reverse_op = 0;
    
        if (v->ob_type != w->ob_type &&
            PyType_IsSubtype(w->ob_type, v->ob_type) &&
            (f = w->ob_type->tp_richcompare) != NULL) {     // 检查v,w的两个类型是否相同,检查是否w,v是否是子类型,检查w对应的tp_richcompare是否为空
            checked_reverse_op = 1;                         
            res = (*f)(w, v, _Py_SwappedOp[op]);            // 直接调用w的tp_richcompare方法进行比较
            if (res != Py_NotImplemented)
                return res;                                 // 返回结果
            Py_DECREF(res);
        }
        if ((f = v->ob_type->tp_richcompare) != NULL) {     // 检查v是否有tp_richcompare方法
            res = (*f)(v, w, op);                           // 调用v的tp_richcompare进行比较
            if (res != Py_NotImplemented)                   
                return res;                                 // 返回结果    
            Py_DECREF(res);
        }
        if (!checked_reverse_op && (f = w->ob_type->tp_richcompare) != NULL) { // 如果checked_reverse_op为0,w的tp_richcompare不为空
            res = (*f)(w, v, _Py_SwappedOp[op]);            // 调用w的tp_richcompare方法进行比较
            if (res != Py_NotImplemented)
                return res;                                 // 返回结果
            Py_DECREF(res);
        }
        /* If neither object implements it, provide a sensible default
           for == and !=, but raise an exception for ordering. */
        switch (op) {                                       // 如果都没有实现该方法则使用简易的默认方法
        case Py_EQ:
            res = (v == w) ? Py_True : Py_False;            // 判断是否相等
            break;
        case Py_NE:
            res = (v != w) ? Py_True : Py_False;            // 判断是否相等
            break;
        default:
            /* XXX Special-case None so it doesn't show as NoneType() */
            PyErr_Format(PyExc_TypeError,
                         "unorderable types: %.100s() %s %.100s()",
                         v->ob_type->tp_name,
                         opstrings[op],
                         w->ob_type->tp_name);
            return NULL;
        }
        Py_INCREF(res);
        return res;                                         // 返回结果
    }
    

    由于此时列表a中的元素是long型的元素,则调用了long_richcompare方法进行两个值之间的比较,

    static PyObject *
    long_richcompare(PyObject *self, PyObject *other, int op)
    {
        int result;
        PyObject *v;
        CHECK_BINOP(self, other);
        if (self == other)                                                      // 如果两者相等
            result = 0;                                                         // 直接返回
        else
            result = long_compare((PyLongObject*)self, (PyLongObject*)other);   // 比较两个long型
        /* Convert the return value to a Boolean */
        switch (op) {                                                           // 根据op 返回不同的结果
        case Py_EQ:
            v = TEST_COND(result == 0);
            break;
        case Py_NE:
            v = TEST_COND(result != 0);
            break;
        case Py_LE:
            v = TEST_COND(result <= 0);
            break;
        case Py_GE:
            v = TEST_COND(result >= 0);
            break;
        case Py_LT:
            v = TEST_COND(result == -1);
            break;
        case Py_GT:
            v = TEST_COND(result == 1);
            break;
        default:
            PyErr_BadArgument();
            return NULL;
        }
        Py_INCREF(v);
        return v;
    }
    

    其中又调用了long_compare函数进行比较,

    static int
    long_compare(PyLongObject *a, PyLongObject *b)
    {
        Py_ssize_t sign;
    
        if (Py_SIZE(a) != Py_SIZE(b)) {             // 比较大小是否相同
            sign = Py_SIZE(a) - Py_SIZE(b);         // 获取两个值的差值
        }
        else {
            Py_ssize_t i = Py_ABS(Py_SIZE(a));      // 获取a值大小
            while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
                ;
            if (i < 0)
                sign = 0;
            else {
                sign = (sdigit)a->ob_digit[i] - (sdigit)b->ob_digit[i];
                if (Py_SIZE(a) < 0)
                    sign = -sign;
            }
        }
        return sign < 0 ? -1 : sign > 0 ? 1 : 0;    // 根据sign的处理结果返回
    }
    

    至此就比较出来了两个值的大小,如果相同则会继续执行listremove
    中的list_ass_slice函数,将对应索引位置的值置空,该函数具体的执行流程大家可自行阅读,至此一个列表中的元素的删除过程已经分析完成。

    总结

    列表的初始化和插入数据和删除数据基本上的流程分析完成,其中还有很多其他的细节在流程中没有涉及到,列表在元素增长或者减少的过程中,都会涉及到都申请得到内存进行相关操作,此时的大量细节还需要大家自行查看。

    展开全文
  • Python源码分析1 - Building Python

    千次阅读 2013-12-08 23:50:47
    Python是一种动态的脚本语言。具体的我就不多介绍了,可以参考www.python.org. Python是Open Source的,在www.python.org可以下载到最新的2.5版的源代码。源代码链接在这里:Python 2.5 下载下来之后直接解压缩可以...

    Python是一种动态的脚本语言。具体的我就不多介绍了,可以参考www.python.org. Python是Open Source的,在www.python.org可以下载到最新的2.5版的源代码。源代码链接在这里:Python 2.5

    下载下来之后直接解压缩可以看到如下的目录结构:

    DemoDemo用的代码,主要用来展示Python的一些应用
    DocPython的UserManual。Latex格式的
    Grammar语法文件。这个语法文件会在Python运行的时候被用来分析Python源代码
    IncludePython Include用的头文件
    LibPython的库文件
    MacFor Mac
    Misc如字面意思,一些不适合放在其他地方的文件就放在这里了
    ModulesPython的一些Built-in Module的实现
    ObjectsPython的基本内部对象的实现,比如class/list等等
    ParserPython的词法分析和语法分析
    PC比较老的Windows和OS2的Port的项目以及Port用到的一些公用文件放在这里,PCBuild和PCBuild8都要用到这个目录的内容
    PCBuildPython用于VS 2003的Project文件
    PCbuild8Python用于VS 2005的Project文件
    PythonPython主程序代码
    RISCOSPython的RISC OS Port
    ToolsBuild和Extend Python所需的工具

    在Unix/Linux/Cywin下面可以直接键入:

    ./configure
    make install

    Windows用VC Build的话,可以直接打开PCBuild/PCBuild8下面相应的Solution来Build。直接Build的话会出不少错误,有必要做一些调整:

    1. 不是所有的Project都可以立刻Build,部分Project由于对第三方库有依赖,一般情况下可以直接跳过Build这些Project,而只Build核心的Python代码。在Configuration Manager里面直接Exclude就可以。必需的Project是:make_buildinfo, make_versioninfo, python, pythoncore
    2. PythoncoreProject少了一个文件,需要手动把Modules/_typesmodule.c加入到工程中去,再Build

    今天就写到这里,下一篇我会通过跟踪执行一个最简单的Python代码来介绍Python执行的流程。 

    展开全文
  • Python 源码分析:queue 队列模块

    千次阅读 2019-05-19 20:29:16
    源码分析 先从初始化的函数来看: 从这初始化函数能得到哪些信息呢?首先,队列是可以设置其容量大小的,并且具体的底层存放元素的它使用了collections.deque()双端列表的数据结构,这使得能很方便的做先进先...

    起步

    queue 模块提供适用于多线程编程的先进先出(FIFO)数据结构。因为它是线程安全的,所以多个线程很轻松地使用同一个实例。

    源码分析

    先从初始化的函数来看:

     

    从这初始化函数能得到哪些信息呢?首先,队列是可以设置其容量大小的,并且具体的底层存放元素的它使用了collections.deque()双端列表的数据结构,这使得能很方便的做先进先出操作。这里还特地抽象为_init函数是为了方便其子类进行覆盖,允许子类使用其他结构来存放元素(比如优先队列使用了 list)。

    然后就是线程锁self.mutex,对于底层数据结构self.queue的操作都要先获得这把锁;再往下是三个条件变量,这三个 Condition 都以self.mutex作为参数,也就是说它们共用一把锁;从这可以知道诸如with self.mutex与with self.not_empty等都是互斥的。

    基于这些锁而做的一些简单的操作:

     

    这个代码片段挺好理解的,无需分析。

    作为队列,主要得完成入队与出队的操作,首先是入队:

     

    尽管只有二十几行的代码,但这里的逻辑还是比较复杂的。它要处理超时与队列剩余空间不足的情况,具体几种情况如下:

    1、如果 block 是 False,忽略timeout参数

    若此时队列已满,则抛出 Full 异常;

    若此时队列未满,则立即把元素保存到底层数据结构中;

    2、如果 block 是 True

    若 timeout 是 None 时,那么put操作可能会阻塞,直到队列中有空闲的空间(默认);

    若 timeout 是非负数,则会阻塞相应时间直到队列中有剩余空间,在这个期间,如果队列中一直没有空间,抛出 Full 异常;

    处理好参数逻辑后,,将元素保存到底层数据结构中,并递增unfinished_tasks,同时通知not_empty,唤醒在其中等待数据的线程。

    出队操作:

     

    get()操作是put()相反的操作,代码块也及其相似,get()是从队列中移除最先插入的元素并将其返回。

    1、如果 block 是 False,忽略timeout参数

    若此时队列没有元素,则抛出 Empty 异常;

    若此时队列由元素,则立即把元素保存到底层数据结构中;

    2、如果 block 是 True

    若 timeout 是 None 时,那么get操作可能会阻塞,直到队列中有元素(默认);

    若 timeout 是非负数,则会阻塞相应时间直到队列中有元素,在这个期间,如果队列中一直没有元素,则抛出 Empty 异常;

    最后,通过self.queue.popleft()将最早放入队列的元素移除,并通知not_full,唤醒在其中等待数据的线程。

    这里有个值得注意的地方,在put()操作中递增了self.unfinished_tasks,而get()中却没有递减,这是为什么?

    这其实是为了留给用户一个消费元素的时间,get()仅仅是获取元素,并不代表消费者线程处理的该元素,用户需要调用task_done()来通知队列该任务处理完成了:

     

    由于task_done()使用方调用的,当task_done()次数大于put()次数时会抛出异常。

    task_done()操作的作用是唤醒正在阻塞的join()操作。join()方法会一直阻塞,直到队列中所有的元素都被取出,并被处理了(和线程的join方法类似)。也就是说join()方法必须配合task_done()来使用才行。

    LIFO 后进先出队列

    LifoQueue使用后进先出顺序,与栈结构相似:

     

    这就是 LifoQueue 全部代码了,这正是 Queue 设计很棒的一个原因,它将底层的数据操作抽象成四个操作函数,本身来处理线程安全的问题,使得其子类只需关注底层的操作。

    LifoQueue 底层数据结构改用 list 来存放,通过 self.queue.pop() 就能将 list 中最后一个元素移除,无需重置索引。

    PriorityQueue 优先队列

     

    优先队列使用了 heapq 模块的结构,也就是最小堆的结构。优先队列更为常用,队列中项目的处理顺序需要基于这些项目的特征,一个简单的例子:

     

    使用优先队列的时候,需要定义__lt__魔术方法,来定义它们之间如何比较大小。若元素的 priority 相同,依然使用先进先出的顺序。

    参考

    https://pymotw.com/3/queue/index.html

    展开全文
  • Python源码学习:Python类机制分析

    千次阅读 2018-04-07 10:44:20
    Python源码分析本文环境python2.5系列 参考书籍<<Python源码剖析>> 本文主要分析Python中类时如何实现的,在Python中,一切都是对象;任何对象都有一个type,都可以通过class属性,一般情况下为type对应于Python源码...

    Python源码分析

    本文环境python2.5系列
    参考书籍<<Python源码剖析>>
    

    本文主要分析Python中类时如何实现的,在Python中,一切都是对象;任何对象都有一个type,都可以通过class属性,一般情况下为type对应于Python源码中的PyType_Type;在Python的类中,都直接或者间接与Object有关联,都是Object的子类,对应Python中PyBaseObject_Type。在Python的启动执行流程一文中有介绍,在Python启动的过程中会首先对默认的类型进行初始化,我们就从这里开始分析。

    分析

    初始化代码如下;

    void
    _Py_ReadyTypes(void)
    {
        if (PyType_Ready(&PyType_Type) < 0)
            Py_FatalError("Can't initialize 'type'");
    
        if (PyType_Ready(&_PyWeakref_RefType) < 0)
            Py_FatalError("Can't initialize 'weakref'");
    
        if (PyType_Ready(&PyBool_Type) < 0)
            Py_FatalError("Can't initialize 'bool'");
    
        if (PyType_Ready(&PyString_Type) < 0)
            Py_FatalError("Can't initialize 'str'");
    
        if (PyType_Ready(&PyList_Type) < 0)
            Py_FatalError("Can't initialize 'list'");
    
        if (PyType_Ready(&PyNone_Type) < 0)
            Py_FatalError("Can't initialize type(None)");
    
        if (PyType_Ready(&PyNotImplemented_Type) < 0)
            Py_FatalError("Can't initialize type(NotImplemented)");
    }

    这里分析下PyType_Ready(&PyType_Type)初始化过程,首先我们查看下PyType_Type类型的结构;

    PyTypeObject PyType_Type = {
        PyObject_HEAD_INIT(&PyType_Type)      //  类型还是PyType_Type
        0,                  /* ob_size */
        "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 */
        type_compare,               /* 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 */    // 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,        /* tp_flags */
        type_doc,               /* tp_doc */
        (traverseproc)type_traverse,        /* tp_traverse */
        (inquiry)type_clear,            /* tp_clear */
        0,                  /* 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 */
        0,                  /* tp_init */
        0,                  /* tp_alloc */
        type_new,               /* tp_new */
        PyObject_GC_Del,                /* tp_free */
        (inquiry)type_is_gc,            /* tp_is_gc */
    };

    由此可见type定义中的tp_base为空,在初始化过程中就会将基类换成Object;我们看完定义后再查看初始化过程;

    int
    PyType_Ready(PyTypeObject *type)
    {
        PyObject *dict, *bases;
        PyTypeObject *base;
        Py_ssize_t i, n;
    
        if (type->tp_flags & Py_TPFLAGS_READY) {
            assert(type->tp_dict != NULL);
            return 0;
        }
        assert((type->tp_flags & Py_TPFLAGS_READYING) == 0);
    
        type->tp_flags |= Py_TPFLAGS_READYING;
    
    #ifdef Py_TRACE_REFS
        /* PyType_Ready is the closest thing we have to a choke point
         * for type objects, so is the best place I can think of to try
         * to get type objects into the doubly-linked list of all objects.
         * Still, not all type objects go thru PyType_Ready.
         */
        _Py_AddToAllObjects((PyObject *)type, 0);
    #endif
    
        /* Initialize tp_base (defaults to BaseObject unless that's us) */
        base = type->tp_base;                                       // 获取初始化类型的基类
        if (base == NULL && type != &PyBaseObject_Type) {           // 如果基类为空,并且初始化的类型不为Object
            base = type->tp_base = &PyBaseObject_Type;              // 将初始化类的基类设置成Object
            Py_INCREF(base);
        }
    
            /* Now the only way base can still be NULL is if type is
             * &PyBaseObject_Type.
             */
    
        /* Initialize the base class */
        if (base && base->tp_dict == NULL) {                        // 如果基类的属性列表为空
            if (PyType_Ready(base) < 0)                             // 初始化基类
                goto error;
        }
    
        /* Initialize ob_type if NULL.  This means extensions that want to be
           compilable separately on Windows can call PyType_Ready() instead of
           initializing the ob_type field of their type objects. */
            /* The test for base != NULL is really unnecessary, since base is only
               NULL when type is &PyBaseObject_Type, and we know its ob_type is
               not NULL (it's initialized to &PyType_Type).  But coverity doesn't
               know that. */
        if (type->ob_type == NULL && base != NULL)                 // 如果初始化类型的类型为空,并且基类不为空
            type->ob_type = base->ob_type;                         // 初始化类型的类型设置成基类的类型
    
        /* Initialize tp_bases */
        bases = type->tp_bases;                                    // 获取初始化类型的基类列表
        if (bases == NULL) {                                       // 如果基类列表为空
            if (base == NULL)                                      // 如果父类为空
                bases = PyTuple_New(0);                            // 基类则生成一个空的元组
            else
                bases = PyTuple_Pack(1, base);                     // 如果基类不为空,生成长度为1的元组,并将base发入其中
            if (bases == NULL)
                goto error;
            type->tp_bases = bases;                                // 将生成的bases设置到初始化类型中
        }
    
        /* Initialize tp_dict */
        dict = type->tp_dict;                                      // 获取类型的属性列表
        if (dict == NULL) {                                        
            dict = PyDict_New();                                   // 如果属性为空,则生成一个字典,并设置到初始化类型中
            if (dict == NULL)
                goto error;
            type->tp_dict = dict;
        }
    
        /* Add type-specific descriptors to tp_dict */
        if (add_operators(type) < 0)                               // 给该类型添加描述方法
            goto error;
        if (type->tp_methods != NULL) {
            if (add_methods(type, type->tp_methods) < 0)           // 如果类型方法不为空,则将方法包装后添加到初始化类型中
                goto error;
        }
        if (type->tp_members != NULL) {
            if (add_members(type, type->tp_members) < 0)           // 如果类型成员不为空,则将成员包装后添加到初始化类型中
                goto error;
        }
        if (type->tp_getset != NULL) {
            if (add_getset(type, type->tp_getset) < 0)             
                goto error;
        }
    
        /* Calculate method resolution order */
        if (mro_internal(type) < 0) {                              // 获取初始化类型的基础列表
            goto error;
        }
    
        /* Inherit special flags from dominant base */
        if (type->tp_base != NULL)
            inherit_special(type, type->tp_base);                  // 如果基类不为空,则继承基类的方法属性等
    
        /* Initialize tp_dict properly */
        bases = type->tp_mro;                                      // 获取初始化类型的基础列表
        assert(bases != NULL);    
        assert(PyTuple_Check(bases));
        n = PyTuple_GET_SIZE(bases);
        for (i = 1; i < n; i++) {
            PyObject *b = PyTuple_GET_ITEM(bases, i);              // 依次获取基础列表的值
            if (PyType_Check(b))
                inherit_slots(type, (PyTypeObject *)b);            // 继承相应的方法
        }
    
        /* Sanity check for tp_free. */
        if (PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) &&
            (type->tp_free == NULL || type->tp_free == PyObject_Del)) {
                /* This base class needs to call tp_free, but doesn't have
                 * one, or its tp_free is for non-gc'ed objects.
                 */
            PyErr_Format(PyExc_TypeError, "type '%.100s' participates in "
                     "gc and is a base type but has inappropriate "
                     "tp_free slot",
                     type->tp_name);
            goto error;
        }
    
        /* if the type dictionary doesn't contain a __doc__, set it from
           the tp_doc slot.
         */
        if (PyDict_GetItemString(type->tp_dict, "__doc__") == NULL) {    // 设置属性的__doc__属性,如果有设置其中,如果没有则设置为空
            if (type->tp_doc != NULL) {
                PyObject *doc = PyString_FromString(type->tp_doc);
                if (doc == NULL)
                    goto error;
                PyDict_SetItemString(type->tp_dict, "__doc__", doc);
                Py_DECREF(doc);
            } else {
                PyDict_SetItemString(type->tp_dict,
                             "__doc__", Py_None);
            }
        }
    
        /* Some more special stuff */
        base = type->tp_base;                                       // 获取基类,如果子类相应的方法为空,则直接将基类方法设置给初始化类型
        if (base != NULL) {
            if (type->tp_as_number == NULL)
                type->tp_as_number = base->tp_as_number;
            if (type->tp_as_sequence == NULL)
                type->tp_as_sequence = base->tp_as_sequence;
            if (type->tp_as_mapping == NULL)
                type->tp_as_mapping = base->tp_as_mapping;
            if (type->tp_as_buffer == NULL)
                type->tp_as_buffer = base->tp_as_buffer;
        }
    
        /* Link into each base class's list of subclasses */
        bases = type->tp_bases;                                    // 获取初始化类型的基类列表,
        n = PyTuple_GET_SIZE(bases);
        for (i = 0; i < n; i++) {
            PyObject *b = PyTuple_GET_ITEM(bases, i);            
            if (PyType_Check(b) &&
                add_subclass((PyTypeObject *)b, type) < 0)         // 将初始化类型添加到基类中,填充基类子类列表
                goto error;
        }
    
        /* All done -- set the ready flag */
        assert(type->tp_dict != NULL);
        type->tp_flags =
            (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;   // 设置该类型已经初始化完成
        return 0;
    
      error:
        type->tp_flags &= ~Py_TPFLAGS_READYING;
        return -1;
    }

    其中,主要经历了五个不中
    1.设置type信息,基类及基类列表;
    2.填充tp_dict;
    3.确定mro;
    4.从mro列表继承基类属性;
    5.设置基类的子类列表。
    其中我们从初始化完成tp_dict后填充方法开始分析;

        /* Add type-specific descriptors to tp_dict */
        if (add_operators(type) < 0)                               // 给该类型添加描述方法
            goto error;
        if (type->tp_methods != NULL) {
            if (add_methods(type, type->tp_methods) < 0)           // 如果类型方法不为空,则将方法包装后添加到初始化类型中
                goto error;
        }
        if (type->tp_members != NULL) {
            if (add_members(type, type->tp_members) < 0)           // 如果类型成员不为空,则将成员包装后添加到初始化类型中
                goto error;
        }
        if (type->tp_getset != NULL) {
            if (add_getset(type, type->tp_getset) < 0)             
                goto error;
        }

    查看add_operators(type)方法;

    static int
    add_operators(PyTypeObject *type)
    {
        PyObject *dict = type->tp_dict;
        slotdef *p;
        PyObject *descr;
        void **ptr;
    
        init_slotdefs();                        // 排序slotdefs数组
        for (p = slotdefs; p->name; p++) {      // 获取slotdefs的值
            if (p->wrapper == NULL)             // 如果包装的函数为空,则直接获取下一个
                continue;
            ptr = slotptr(type, p->offset);     // 转换获取相应的方法
            if (!ptr || !*ptr)
                continue;
            if (PyDict_GetItem(dict, p->name_strobj))   // 如果在属性列表中获取到相应名称,则不覆盖直接下一个
                continue;
            descr = PyDescr_NewWrapper(type, p, *ptr);   // 将该方法生成一个新的描述符
            if (descr == NULL)
                return -1;
            if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)   // 将生成的描述符设置到对应的属性列表中
                return -1;
            Py_DECREF(descr);
        }
        if (type->tp_new != NULL) {
            if (add_tp_new_wrapper(type) < 0)
                return -1;
        }
        return 0;
    }

    这其中出现了init_slotdefs,这在Python中有一个叫slot,一个slot对应一个方法。其定义如下;

    typedef struct wrapperbase slotdef;
    
    struct wrapperbase {
        char *name;                 // 名称
        int offset;                 // 偏移,相对于PyHead-TypeObject
        void *function;             // 包装的函数
        wrapperfunc wrapper;        
        char *doc;                  // 文档
        int flags;        
        PyObject *name_strobj;     // 对应名称转换为字符串对象
    };

    对于slotdef,提供了多种宏来定义一个slotdef

    #define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \
        {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
         PyDoc_STR(DOC), FLAGS}
    #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
        {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
         PyDoc_STR(DOC)}

    两个方法的不同就是一个相对于PyTypeObject,一个相对于PyHeapTypeObject,两个偏移量相对偏移的类型不同。其中PyHeapTypeObject定义如下;

    typedef struct _heaptypeobject {
        /* Note: there's a dependency on the order of these members
           in slotptr() in typeobject.c . */
        PyTypeObject ht_type;
        PyNumberMethods as_number;
        PyMappingMethods as_mapping;
        PySequenceMethods as_sequence; /* as_sequence comes after as_mapping,
                          so that the mapping wins when both
                          the mapping and the sequence define
                          a given operator (e.g. __getitem__).
                          see add_operators() in typeobject.c . */
        PyBufferProcs as_buffer;
        PyObject *ht_name, *ht_slots;
        /* here are optional user slots, followed by the members. */
    } PyHeapTypeObject;

    为什么会有这个区别是因为在一个PyTypeObject对象中,对应的操作方法比如nb_add是存放在函数指针tp_as_number中,而这是另外一个结构,无法计算出nb_add相对于PyTypeObject的相对位置,由PyHeapTypeObject可以看出,可以直接计算相对位置。
    接下来查看下slotdefs数组;

    static slotdef slotdefs[] = {
        SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc,
               "x.__len__() <==> len(x)"),
        /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
           The logic in abstract.c always falls back to nb_add/nb_multiply in
           this case.  Defining both the nb_* and the sq_* slots to call the
           user-defined methods has unexpected side-effects, as shown by
           test_descr.notimplemented() */
        SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,
              "x.__add__(y) <==> x+y"),
        SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc,
              "x.__mul__(n) <==> x*n"),
        SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc,
              "x.__rmul__(n) <==> n*x"),
        ...
        SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
               "x.__getitem__(y) <==> x[y]"),
        ...
        MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
               wrap_binaryfunc,
               "x.__getitem__(y) <==> x[y]"),
        ...
    }

    其中,可以发现有不同名的操作,也有同名的操作,对应于同名的操作是如何做选择呢,此时如果是PyTypeObject,此时相对于PyHeapTypeObject,其中as_mapping在as_sequence上面,所有mp_subscript的排序会比sq_item靠前,所以会选择mp_subscript。
    此时继续查看init_slotdefs代码;

    static void
    init_slotdefs(void)
    {
        slotdef *p;
        static int initialized = 0;
    
        if (initialized)
            return;
        for (p = slotdefs; p->name; p++) {
            p->name_strobj = PyString_InternFromString(p->name);     // 将名称转换为Python内部字符串
            if (!p->name_strobj)
                Py_FatalError("Out of memory interning slotdef names");
        }
        qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef),
              slotdef_cmp);                                         // 按照slot_cmp函数规则排序
        initialized = 1;
    }

    然后执行如下代码;

        for (p = slotdefs; p->name; p++) {      // 获取slotdefs的值
            if (p->wrapper == NULL)             // 如果包装的函数为空,则直接获取下一个
                continue;
            ptr = slotptr(type, p->offset);     // 转换获取相应的方法
            if (!ptr || !*ptr)
                continue;
            if (PyDict_GetItem(dict, p->name_strobj))   // 如果在属性列表中获取到相应名称,则不覆盖直接下一个
                continue;
            descr = PyDescr_NewWrapper(type, p, *ptr);   // 将该方法生成一个新的描述符
            if (descr == NULL)
                return -1;
            if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)   // 将生成的描述符设置到对应的属性列表中
                return -1;

    这里可以看到当需要在tp_dict中设置属性时,并不是直接向slotdef直接设置到属性中,而是通过PyDescr_NewWrapper生成一个描述符放置在tp_dict中,为何要这么设计呢?
    我们先查看PyDescr_NewWrapper;

    PyObject *
    PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
    {
        PyWrapperDescrObject *descr;
    
        descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
                             type, base->name);
        if (descr != NULL) {
            descr->d_base = base;                // slotdef 
            descr->d_wrapped = wrapped;          // 被包装的函数
        }
        return (PyObject *)descr;
    }

    继续查看descr_new;

    static PyDescrObject *
    descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
    {
        PyDescrObject *descr;
    
        descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
        if (descr != NULL) {
            Py_XINCREF(type);
            descr->d_type = type;        // 设置装饰的类型
            descr->d_name = PyString_InternFromString(name);  // 设置被装饰的名称
            if (descr->d_name == NULL) {
                Py_DECREF(descr);
                descr = NULL;
            }
        }
        return descr;
    }

    由此查看PyDescrObject类型;

    #define PyDescr_COMMON \
        PyObject_HEAD \
        PyTypeObject *d_type; \
        PyObject *d_name
    
    typedef struct {
        PyDescr_COMMON;
        struct wrapperbase *d_base;
        void *d_wrapped; /* This can be any function pointer */
    } PyWrapperDescrObject;
    

    由此可知一个descr是一个type类型的对象,为什么要转换为一个type类型呢,当调用tp_dict的方法时,需要调用其中tp_call方法,而slotdef并不是一个可调用对象,并不符合可调用的要求。
    在以上流程中,比较重要的就是怎样获取对应的ptr然后生成wrapper存入tp_dict中,

    ptr = slotptr(type, p->offset);     // 转换获取相应的方法

    对应的方法为

    static void **
    slotptr(PyTypeObject *type, int ioffset)
    {
        char *ptr;
        long offset = ioffset;
    
        /* Note: this depends on the order of the members of PyHeapTypeObject! */
        assert(offset >= 0);
        assert((size_t)offset < offsetof(PyHeapTypeObject, as_buffer));
        if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) {
            ptr = (char *)type->tp_as_sequence;
            offset -= offsetof(PyHeapTypeObject, as_sequence);
        }
        else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_mapping)) {
            ptr = (char *)type->tp_as_mapping;
            offset -= offsetof(PyHeapTypeObject, as_mapping);
        }
        else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_number)) {
            ptr = (char *)type->tp_as_number;
            offset -= offsetof(PyHeapTypeObject, as_number);
        }
        else {
            ptr = (char *)type;
        }
        if (ptr != NULL)
            ptr += offset;
        return (void **)ptr;
    }

    此时,从上至下,依次是PyHeapTypeObject对应的as_sequence,as_mapping,as_number,这是因为offset的偏移是从大到小进行检查,因为as_sequence的距离是最远的,如果比as_sequence还小则再检查as_mapping,如果比as_mapping还小则检查as_number,这样就可以查找出对应偏移量对应的方法。
    此时tp_dict属性字典方法填充完成。
    当tp_dict完成后类继承相关的操作
    由于Python中的类的基础是一句传入的参数依次从左至右开始继承;

    >>> class A(object):
    ...     pass
    ... 
    >>> class B(object):
    ...     pass
    ... 
    >>> A.__mro__
    (<class '__main__.A'>, <type 'object'>)
    >>> class C(B,A):
    ...     pass
    ... 
    >>> class D(C,A):
    ...     pass
    ... 
    >>> D.__mro__
    (<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
    >>> D.__bases__
    (<class '__main__.C'>, <class '__main__.A'>)
    >>> C.__mro__
    (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
    >>> 

    可见D的继承顺序是从左至右,依次继承初始化,
    继承的代码执行流程如下;

        /* Initialize tp_dict properly */
        bases = type->tp_mro;                                      // 获取初始化类型的基础列表
        assert(bases != NULL);    
        assert(PyTuple_Check(bases));
        n = PyTuple_GET_SIZE(bases);
        for (i = 1; i < n; i++) {
            PyObject *b = PyTuple_GET_ITEM(bases, i);              // 依次获取基础列表的值
            if (PyType_Check(b))
                inherit_slots(type, (PyTypeObject *)b);            // 继承相应的方法
        }

    由例子可知,tp_mro的第一项是自身,所以i=1开始,依次获取对应的基类,然后执行,inherit_slots,该函数主要就是检查基类中对应的方法子类中是否拥有,如果没有拥有则拷贝到子类中对应的方法中去,以此达到继承父类方法的功能,主要是一些方法的拷贝有兴趣可自行查看。
    接着就将子类添加到基类的子类列表中

        bases = type->tp_bases;                                    // 获取初始化类型的基类列表,
        n = PyTuple_GET_SIZE(bases);
        for (i = 0; i < n; i++) {
            PyObject *b = PyTuple_GET_ITEM(bases, i);            
            if (PyType_Check(b) &&
                add_subclass((PyTypeObject *)b, type) < 0)         // 将初始化类型添加到基类中,填充基类子类列表
                goto error;
        }

    其中调用add_subclass时还生成了Python中的引用相关的操作,有兴趣课自行查看。
    至此初始化就完成,一个PyTypeObject的初始化工作就已经完成,初始化内置类型的操作流程基本分析完成。

    展开全文
  • Python源码分析5 – 语法分析器PyParser

    千次阅读 2013-12-08 23:53:07
    上一篇文章我们分析Python是如何对语法文件Grammar进行预处理,生成语法数据,并在运行时生成Acclerators加速语法分析的过程。当分析完这些内容之后,下一步便是分析Python中语法分析的机制。回顾一下Python的整个...
  • 本文参考的是3.8.0a0 版本的代码,详见cpython 源码分析 基本篇 以后都在 github 更新,请参考图解 python list 用过python 的童鞋都知道 python 内建了好几种数据结构,其中一种就是 list,你可以通过如下的方法...
  • Python源码分析1 - Building Python 分类: Python源码分析2006-11-19 21:40 6808人阅读 评论(6) 收藏 举报 pythonbuildincludewindowsmanagermodule Python是一种动态的脚本语言。具体的我就不...
  • python3.5源码分析-启动与虚拟机

    千次阅读 2018-08-05 16:39:24
    Python3源码分析 本文环境python3.5.2。 参考书籍&lt;&lt;Python源码剖析&gt;&gt; python官网 Python3启动流程概述 本文基于python3分析其基本的运行过程。作为一门动态语言,python脚本在...
  • 4 0 BUILD_MAP 2 3 LOAD_CONST 0 ('a') 6 LOAD_CONST 1 ('1') 9 STORE_MAP 10 LOAD_CONST 2 ('b') 13 LOAD_CONST 3 ('2') ... 29 BUILD_LIST 3 32 STORE_NAME 0 (c) 35 LOAD_CONST 7 (None) 38 RETURN_VALUE
  • 课程亮点了解Python运行机制和设计思想;熟悉背后的数据结构和算法原理;结合工程实际,掌握高效程序设计之道;高级面试知识点,求职更自信;大量图表辅助学习,难点知识轻松拿下。课程简介能用Python完成开发需求,...
  • python源码分析----对象结构

    千次阅读 2015-05-18 12:51:49
    python中,所有的东西都是对象,整数是,方法也是,。。总之什么都是。。。。 在看python的代码实现中,可以随处看到指针类型:PyObject*,那么我们就先来看看PyObject这到底是怎么定义的吧:
  • python源码分析----内存分配(1)

    千次阅读 2015-05-19 23:21:18
    上面的一篇粗略的介绍了一下python的对象结构,这篇来分析一个非常重要的部分,内存分配。。。 好像自己看的源代码,只要是跟C语言相关的,都在内存处理方面做了相当多的工作。。。。例如nginx,它也有实现自己的...
  • Python3源码分析 本文环境python3.5.2。 参考书籍&amp;lt;&amp;lt;Python源码剖析&amp;gt;&amp;gt; python官网 Python3模块初始化与加载 Python的模块分为内建的模块,函数与用户定义的模块,...
  • list是动态长度的,在必要时会重新分配内存 这里的* 和 *=是两个不同的指令,不同的指令导致分配的内存不一样。 a * 10 是将会调用list_repeat 所以a * 10只会申请容纳10个元素的空间 而 *= 会调用 list_in...
  • Python3源码分析 本文环境python3.5.2。 参考书籍&lt;&lt;Python源码剖析&gt;&gt; python官网 Python3的sys模块初始化 根据分析完成builtins初始化后,继续分析sys模块的初始化,继续分析_Py_...
  • python3.7源码分析-字典

    千次阅读 2019-05-22 16:43:36
    python字典 Dictionary object implementation using a hash table ,通过描述可知,python的字典就是实现了一个hash表。 Python字典概述 在python的字典中,一个键值对的对应保存就是PyDictEntry类型来保存; ...
  • Python Unittest源码分析

    千次阅读 2014-03-16 20:23:25
    Unittest,即Unit testing framework(也可以称为...PyUnit是Python版的JUnit,但是2.1版的PyUnit太复杂,不利于理解,这里主要分析 Version 1.2。 PyUnit类包含TestResult,TestCase, TestSuite,TextTestResult,Te
  • Python源码目录

    千次阅读 2017-09-28 10:50:14
    Python源码目录 从Python.org中下载源代码压缩包并解压,我下载的是Python2.7.12,解压后:   对于主要的文件夹做出介绍: Include:包含Python提供的所有头文件,如果需要自己使用C或者C++编写...
  • python3.7源码分析-集合(set)

    千次阅读 2019-06-04 19:38:03
    python集合 set是无序且不重复的集合,是可变的,通常用来从列表中删除重复项以及计算数学运算,如交集、并集、差分和对称差分等集合操作。set 支持 x in set, len(set),和 for x in set。作为一个无序的集合,set不...
  • 很多东西不用就忘记了,比如C语言,正好,python源码用C写的,分析python源码的同时又能温故C语言基础,实在是件很好的事情。另外,还有陈儒大神的《python源码剖析》做指引,分析也不至于没头没脑。期望在一个月的...
  • 关于Python版本的词云wordcloud模块的简单应用和源码分析
  • Python源码剖析笔记2-Python整数对象

    千次阅读 2015-05-24 16:21:52
    Python源码剖析笔记2-Python整数对象本文简书地址: http://www.jianshu.com/p/0136ed90cd46 千里之行始于足下,从简单的类别开始分析,由浅入深也不至于自己丧失信心。先来看看Python整数对象,也就是python中的...
  • 本文参考的是3.8.0a0 版本的代码,详见cpython 源码分析 基本篇 以后都在 github 更新,请参考图解python tuple python 的内建对象除了 list 这个可变的数据结构,还有 tuple 这个不可变的数据结构,不可变的意思...
  • Python源码剖析笔记3-Python执行原理初探 之前写了几篇源码剖析笔记,然而慢慢觉得没有从一个宏观的角度理解python执行原理的话,从底向上分析未免太容易让人疑惑,不如先从宏观上对python执行原理有了一个基本了解...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 34,993
精华内容 13,997
关键字:

listpython源码分析

python 订阅