本篇文章介绍了Python中与列表相关的内建函数,还介绍了列表对象本身所包含的各种与列表操作相关的方法。主要通过例子与相关的C源码,来对这些脚本函数及方法进行讲解。

    页面导航: 英文教程的下载地址:

    本篇文章是根据英文教程《Python Tutorial》来写的学习笔记。该英文教程的下载地址如下:

    百度盘地址:http://pan.baidu.com/s/1c0eXSQG

    DropBox地址:点此进入DropBox链接

    Google Drive:点此进入Google Drive链接

    这是学习笔记,不是翻译,因此,内容上会与英文原著有些不同。以下记录是根据英文教程的第十章来写的。(文章中的部分链接,包括下载链接,可能需要通过代理访问!)

    本篇文章也会涉及到Python的C源代码,这些C源码都是2.7.8版本的。想使用gdb来调试python源代码的话,就需要按照前面"Python基本的操作运算符"文章中所说的,使用configure --with-pydebug命令来重新编译安装python。

    如果Python的官方网站取消了Python-2.7.8.tgz的源码包的话,可以在以下两个链接中下载到:

    DropBox:Python-2.7.8.tgz的DropBox网盘链接

    Google Drive:Python-2.7.8.tgz的Google Drive网盘链接

列表相关的内建函数:

    Python中包含了一些可以对列表进行操作的内建函数,如下表所示:

内建函数 描述信息
cmp(list1, list2) 通过对list1,list2两个列表里的所有成员进行比较,以及两列表的成员数进行比较,从而判断出list1是否大于、等于或者小于list2 。
len(list) 获取list列表的总成员数。
max(list [, key=func]) 通过对list列表中的每个成员对象进行比较,来返回值最大的成员。

如果给max函数提供了key=func的名值对的话,max在从list列表中获取成员时,会先使用func函数将成员转换为需要比较的对象,再进行比较。

max其实可以接受多个参数,当提供多个参数时,就是在这几个参数之间进行比较。比如:max(list1, list2, list3),那么此时就会对list1,list2,list3这三个列表进行比较,并返回最大的列表对象。

只有当max接受一个参数时,如max(list1)时,才会返回list1里最大的成员对象。

Python的脚本函数的参数是不包括名值对在内的。例如:max(list1, key=func)在Python内部执行时,max就只有一个list1参数,key=func是不属于函数参数的,它会被存储到单独的名值对所在的词典里,这在下面分析C源码时会提到。
min(list [, key=func]) 通过对list列表中的每个成员对象进行比较,从而返回最小的成员。
它与max函数一样,可以接受一个可选的key=func的名值对。
并且,min也与max一样可以接受多个参数,当提供多个参数时,就是在这几个参数之间进行比较。
list(seq) 如果参数seq是可迭代的对象,则根据seq里的迭代成员,来创建一个新的列表对象。

    上面这些内建函数除了可以对列表对象进行操作外,还可以对其他类型的对象进行操作。例如:len函数还可以获取字符串对象的尺寸信息等。只不过本章主要介绍的是列表对象,因此,这里都以列表对象为例进行说明。

    下面就对这些内建函数一一进行举例说明。

cmp(list1, list2):

    先看下cmp函数的简单例子:

[email protected]:~$ gdb -q python
....................................................
>>> cmp([1,2,3], [3,4,5])
....................................................

Breakpoint 1, list_richcompare (v=0xb7c956c4, w=0xb7c9fe34, op=2)
    at Objects/listobject.c:2372
2372	    if (!PyList_Check(v) || !PyList_Check(w)) {
(gdb) backtrace 
#0  list_richcompare (v=0xb7c956c4, w=0xb7c9fe34, op=2)
    at Objects/listobject.c:2372
#1  0x08097396 in try_rich_compare (v=0xb7c956c4, w=0xb7c9fe34, op=2)
    at Objects/object.c:622
#2  0x080974cb in try_rich_compare_bool (v=0xb7c956c4, w=0xb7c9fe34, op=2)
    at Objects/object.c:650
#3  0x0809761c in try_rich_to_3way_compare (v=0xb7c956c4, w=0xb7c9fe34)
    at Objects/object.c:684
....................................................
#7  0x080e6e57 in builtin_cmp (self=0x0, args=0xb7d3a84c)
    at Python/bltinmodule.c:429
....................................................
(gdb) c
Continuing.

Breakpoint 1, list_richcompare (v=0xb7c956c4, w=0xb7c9fe34, op=0)
    at Objects/listobject.c:2372
2372	    if (!PyList_Check(v) || !PyList_Check(w)) {
(gdb) 
Continuing.
-1
>>> 


    cmpbltinmodule(内建模块)里的函数,对应的底层C函数为builtin_cmp

    builtin_cmp又会通过try_rich_to_3way_compare来完成比较操作,try_rich_to_3way_compare定义在Objects/object.c文件里:

/* Try rich comparisons to determine a 3-way comparison.  Return:
   -2 for an exception;
   -1 if v  < w;
    0 if v == w;
    1 if v  > w;
    2 if this particular rich comparison is not implemented or undefined.
*/
static int
try_rich_to_3way_compare(PyObject *v, PyObject *w)
{
    static struct { int op; int outcome; } tries[3] = {
        /* Try this operator, and if it is true, use this outcome: */
        {Py_EQ, 0},
        {Py_LT, -1},
        {Py_GT, 1},
    };
    int i;

    if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL)
        return 2; /* Shortcut */

    for (i = 0; i < 3; i++) {
        switch (try_rich_compare_bool(v, w, tries[i].op)) {
        case -1:
            return -2;
        case 1:
            return tries[i].outcome;
        }
    }

    return 2;
}


    上面函数里的两个参数v与w,是需要进行比较的两个对象。在本例中对应为[1,2,3]与[3,4,5]这两个列表对象。

    此外,该函数中还有个tries数组,该数组的3个成员的op字段分别为Py_EQPy_LTPy_GT。在最后的for循环里,会依次将这三个op值传递给try_rich_compare_bool函数,如果哪个op值返回1,则将对应的outcome值作为结果返回。

    例如:当传递Py_EQ时,如果try_rich_compare_bool返回1的话,就说明v与w相等,结果就会将对应的outcome0返回。

    如果v与w不相等,则继续传递Py_LT,判断v是否小于w,如果v小于w,则结果返回-1

    如果v不小于w的话,最后再传递Py_GT,判断v是否大于w,如果v大于w,则结果返回1

    因此,前面例子中的 cmp([1,2,3], [3,4,5]) 脚本执行后,输出结果为-1,则说明[1,2,3]小于[3,4,5]。

    从前面gdb的backtrace输出中可以看到,try_rich_compare_bool函数会进入到try_rich_compare函数,该函数则会根据不同类型的对象,调用不同的底层函数去完成具体的比较操作。

    如果是列表类型的对象,则最终会进入到list_richcompare函数来完成比较操作,该函数定义在Objects/listobject.c文件中:

static PyObject *
list_richcompare(PyObject *v, PyObject *w, int op)
{
    PyListObject *vl, *wl;
    Py_ssize_t i;

    // 需要进行比较的两个对象v与w
    // 必须都是列表类型
    if (!PyList_Check(v) || !PyList_Check(w)) {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    // 将v与w转为列表对象指针
    vl = (PyListObject *)v;
    wl = (PyListObject *)w;

    // 当op为Py_EQ或Py_NE时,
    // (判断列表是否相等或者是否不相等时)
    // 如果两个列表的尺寸(拥有的成员数)不相同时,
    // 则说明这两个列表肯定不相等,
    // 就可以直接将结果返回。
    // 对于Py_EQ,直接返回False,
    // 对于Py_NE,直接返回True
    if (Py_SIZE(vl) != Py_SIZE(wl) && (op == Py_EQ || op == Py_NE)) {
        /* Shortcut: if the lengths differ, the lists differ */
        PyObject *res;
        if (op == Py_EQ)
            res = Py_False;
        else
            res = Py_True;
        Py_INCREF(res);
        return res;
    }

    // 从两个列表的尺寸范围内,
    // 搜索第一个不相等的成员的索引值。
    /* Search for the first index where items are different */
    for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
        int k = PyObject_RichCompareBool(vl->ob_item[i],
                                         wl->ob_item[i], Py_EQ);
        if (k < 0)
            return NULL;
        if (!k)
            break;
    }

    // 如果在两列表的尺寸范围内,
    // 没有找到不相等的成员的话,
    // 则哪个列表的尺寸长,那么该列表就大。
    // 例如:[1,2,3,4] > [1,2,3]
    // 如果两个列表的尺寸相同,则这两个列表就相等。
    // 下面的switch...case语句只需要
    // 针对不同的op,返回不同的结果即可。
    if (i >= Py_SIZE(vl) || i >= Py_SIZE(wl)) {
        /* No more items to compare -- compare sizes */
        Py_ssize_t vs = Py_SIZE(vl);
        Py_ssize_t ws = Py_SIZE(wl);
        int cmp;
        PyObject *res;
        switch (op) {
        case Py_LT: cmp = vs <  ws; break;
        case Py_LE: cmp = vs <= ws; break;
        case Py_EQ: cmp = vs == ws; break;
        case Py_NE: cmp = vs != ws; break;
        case Py_GT: cmp = vs >  ws; break;
        case Py_GE: cmp = vs >= ws; break;
        default: return NULL; /* cannot happen */
        }
        if (cmp)
            res = Py_True;
        else
            res = Py_False;
        Py_INCREF(res);
        return res;
    }

    // 如果在两列表的尺寸范围内,
    // 找到了不相等的成员,
    // 就说明这两个列表不相等。
    // 那么当op为Py_EQ(判断两列表是否相等)时,
    // 返回False,
    // 当op为Py_NE(判断两列表是否不相等)时, 
    // 则返回True
    /* We have an item that differs -- shortcuts for EQ/NE */
    if (op == Py_EQ) {
        Py_INCREF(Py_False);
        return Py_False;
    }
    if (op == Py_NE) {
        Py_INCREF(Py_True);
        return Py_True;
    }

    // 当op不为Py_EQ或Py_NE时,
    // 就将第一个不相等的成员的比较结果作为
    // 这两个列表的比较结果。
    // 例如:[1,2,3]与[3,4,5]进行比较时,
    // 这两个列表的第一个成员1和3不相等,
    // 那么由于1小于3,
    // 因此,[1,2,3]就小于[3,4,5]了。
    /* Compare the final item again using the proper operator */
    return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
}


len(list):

    该函数在上一篇文章里已经讲解过了,它可以获取到列表中包含的成员个数,它在内部会通过list_length这个C函数来完成具体的操作:

[email protected]:~$ gdb -q python
....................................................
>>> list1
[123, 234, 457, 789]
>>> len(list1)
....................................................

Breakpoint 4, list_length (a=0xb7c956c4) at Objects/listobject.c:434
434	    return Py_SIZE(a);
(gdb) c
Continuing.
4
>>> 


    list_length函数中,又会通过Py_SIZE宏来获取列表的尺寸信息,该宏定义在Include/object.h的头文件里:

#define Py_REFCNT(ob)           (((PyObject*)(ob))->ob_refcnt)
#define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)
#define Py_SIZE(ob)             (((PyVarObject*)(ob))->ob_size)


    Py_SIZE宏其实就是获取的列表对象里的ob_size字段的值,而ob_size字段中就存储了列表中所包含的成员数。

max(list [, key=func])与min(list [, key=func]):

    下面是max函数的简单例子:

[email protected]:~$ gdb -q python
....................................................
>>> list1
[123, 234, 345, 478]
>>> max(list1)
....................................................

Breakpoint 1, builtin_max (self=0x0, args=0xb7d45424, kwds=0x0)
    at Python/bltinmodule.c:1451
1451	    return min_max(args, kwds, Py_GT);
(gdb) s
min_max (args=0xb7d45424, kwds=0x0, op=4) at Python/bltinmodule.c:1348
1348	    PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
....................................................
1366	    it = PyObject_GetIter(v);
(gdb) s
PyObject_GetIter (o=0xb7c956c4) at Objects/abstract.c:3069
3069	    PyTypeObject *t = o->ob_type;
....................................................
(gdb) s
list_iter (seq=0xb7c956c4) at Objects/listobject.c:2869
2869	    if (!PyList_Check(seq)) {
....................................................
(gdb) s
PyIter_Next (iter=0xb7ca1bcc) at Objects/abstract.c:3103
3103	    result = (*iter->ob_type->tp_iternext)(iter);
(gdb) s
listiter_next (it=0xb7ca1bcc) at Objects/listobject.c:2904
2904	    assert(it != NULL);
(gdb) c
Continuing.
478
>>> 


    从调试输出中可以看到,max在内部会通过bltinmodule.c文件里的builtin_max进入min_max函数。在min_max里,会先通过PyObject_GetIter调用list_iter来获取列表相关的迭代器,最后再由listiter_next函数根据迭代器将列表里的每个成员都提取出来进行比较,并将比较得到的最大值作为结果返回。list_iterlistiter_next函数在上一篇文章里,已经讲解过了,这里就不多说了。

    min内建脚本函数的执行过程也是同理:

[email protected]:~$ gdb -q python
....................................................
>>> list1
[123, 234, 345, 478]
>>> min(list1)
....................................................

Breakpoint 2, builtin_min (self=0x0, args=0xb7d45424, kwds=0x0)
    at Python/bltinmodule.c:1437
1437	    return min_max(args, kwds, Py_LT);
(gdb) s
min_max (args=0xb7d45424, kwds=0x0, op=0) at Python/bltinmodule.c:1348
1348	    PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
....................................................
(gdb) s
list_iter (seq=0xb7c956c4) at Objects/listobject.c:2869
2869	    if (!PyList_Check(seq)) {
....................................................
(gdb) s
listiter_next (it=0xb7ca1b94) at Objects/listobject.c:2904
2904	    assert(it != NULL);
(gdb) c
Continuing.
123
>>> 


    只不过min在进行迭代比较后,是将值最小的成员对象给获取出来。

    从上面的调试中可以看到,minmax在内部最终都是通过min_max这个底层C函数来完成具体的比较操作的,该C函数定义在Python/bltinmodule.c文件里:

static PyObject *
min_max(PyObject *args, PyObject *kwds, int op)
{
    PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
    const char *name = op == Py_LT ? "min" : "max";

    // args元组中存储了传递给min或max脚本函数
    // 的参数,当参数个数大于1时,则将整个args元组
    // 作为需要迭代的对象。
    // 例如:max([1,2,3], [2,3,4], [3,4,5])在执行时,
    // 由于max脚本函数的参数个数为3,大于1,因此,
    // 下面就会将[1,2,3], [2,3,4]及[3,4,5]这三个参数
    // 依次从args元组中获取出来,并通过比较来得到
    // 值最大的列表对象。
    // 本例返回的结果就是[3,4,5]。
    if (PyTuple_Size(args) > 1)
        v = args;
    // 如果只传递了单个参数的话,则将该参数作为
    // 需要进行迭代的对象。
    // 例如:max([1,2,3])在执行时,由于只传递了
    // 一个[1,2,3]的列表参数,因此,下面就只会
    // 对该列表进行迭代,并将列表中值最大的成员
    // 作为结果返回。本例中就会返回3。
    else if (!PyArg_UnpackTuple(args, (char *)name, 1, 1, &v))
        return NULL;

    // 如果向max或min脚本函数传递了名值对的话,
    // 所有的名值对都会存储在kwds词典中。
    // 如果存在名为"key"的名值对的话,
    // 就将该名值对中的值作为keyfunc,
    // keyfunc是用户自定义的脚本函数,在进行比较
    // 之前会先通过keyfunc进行转换,并使用
    // 转换后的对象作为需要进行比较的对象。
    // 如下面这个例子:
    // >>> def myfunc(a):
    // ...   if(a == 5):
    // ...     return 1
    // ...   else:
    // ...     return a
    // ... 
    // >>> max([3,4,5], key = myfunc)
    // 4
    // >>> min([3,4,5], key = myfunc)
    // 5
    // 上面[3,4,5]里的成员在进行比较时,
    // 5会被myfunc转为1再进行比较,因此,
    // 比较后,值最小的反而是5了。
    if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds)) {
        keyfunc = PyDict_GetItemString(kwds, "key");
        if (PyDict_Size(kwds)!=1  ||  keyfunc == NULL) {
            PyErr_Format(PyExc_TypeError,
                "%s() got an unexpected keyword argument", name);
            return NULL;
        }
        Py_INCREF(keyfunc);
    }

    // 从需要进行迭代的对象中获取迭代器。
    it = PyObject_GetIter(v);
    if (it == NULL) {
        Py_XDECREF(keyfunc);
        return NULL;
    }

    // 下面的maxitem与maxval在max脚本函数里,
    // 表示最大项与最大值,
    // 而在min脚本函数中,则表示最小项与最小值。
    // 此外,maxitem是需要进行返回的结果对象。
    // 而maxval则是比较用的对象。
    // 例如,上面那个min([3,4,5], key = myfunc)例子
    // 中,5在比较时,被myfunc转为了1,1会被存储
    // 在maxval中用于比较。而5则作为最终的结果
    // 进行返回。
    maxitem = NULL; /* the result */
    maxval = NULL;  /* the value associated with the result */
    // 从迭代对象中,循环将每个成员获取出来,
    // 并通过比较来获取到值最大的成员。
    while (( item = PyIter_Next(it) )) {
        /* get the value from the key function */
        // 如果有keyfunc则调用keyfunc将item
        // 转为需要进行比较的对象val。
        if (keyfunc != NULL) {
            val = PyObject_CallFunctionObjArgs(keyfunc, item, NULL);
            if (val == NULL)
                goto Fail_it_item;
        }
        // 如果没有keyfunc,则直接使用
        // 原对象item进行比较。
        /* no key function; the value is the item */
        else {
            val = item;
            Py_INCREF(val);
        }

        // 对maxitem与maxval进行初始化。
        /* maximum value and item are unset; set them */
        if (maxval == NULL) {
            maxitem = item;
            maxval = val;
        }
        // 将迭代出来的对象val
        // (该val有可能经过了keyfunc的转换)
        // 与maxval进行比较,

        // 当op为Py_LT(获取最小值),
        // 且val小于maxval时,
        // 就将val作为新的maxval,
        // 并将val对应的item作为新的maxitem。

        // 当op为Py_GT(获取最大值),
        // 且val大于maxval时,
        // 也会将val作为新的maxval,
        // 并将val对应的item作为新的maxitem。

        // 这样,通过循环迭代比较,
        // 就可以将值最小的对象或
        // 值最大的对象给获取出来了。
        /* maximum value and item are set; update them as necessary */
        else {
            int cmp = PyObject_RichCompareBool(val, maxval, op);
            if (cmp < 0)
                goto Fail_it_item_and_val;
            else if (cmp > 0) {
                Py_DECREF(maxval);
                Py_DECREF(maxitem);
                maxval = val;
                maxitem = item;
            }
            else {
                Py_DECREF(item);
                Py_DECREF(val);
            }
        }
    }
    ...............................................
}


list(seq):

    list脚本函数可以将可迭代的对象转为列表,如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> list((1,3,5,7,9))

Breakpoint 2, type_call (type=0x81c3880, args=0xb7c9ff4c, kwds=0x0)
    at Objects/typeobject.c:722
722	    if (type->tp_new == NULL) {
(gdb) s
729	    obj = type->tp_new(type, args, kwds);
(gdb) s
PyType_GenericNew (type=0x81c3880, args=0xb7c9ff4c, kwds=0x0)
    at Objects/typeobject.c:786
786	    return type->tp_alloc(type, 0);
....................................................

Breakpoint 1, list_init (self=0xb7ca1dfc, args=0xb7c9ff4c, kw=0x0)
    at Objects/listobject.c:2441
2441	    PyObject *arg = NULL;
....................................................
2458	        PyObject *rv = listextend(self, arg);
(gdb) s
listextend (self=0xb7ca1dfc, b=0xb7d97934) at Objects/listobject.c:812
812	    if (PyList_CheckExact(b) || PyTuple_CheckExact(b) || (PyObject *)self == b) {
....................................................
(gdb) c
Continuing.
[1, 3, 5, 7, 9]
>>> list("13abc")
['1', '3', 'a', 'b', 'c']
>>> list([3,4,5])
[3, 4, 5]
>>> list("13abc",(1,3,4))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list() takes at most 1 argument (2 given)
>>> list()
[]


    list属于类型转换函数,它最多只能接受一个参数。如果没提供任何参数的话,就会返回一个空列表。如果提供了参数,则该参数必须是可迭代的,例如:tuple元组,str字符串以及list列表等。list脚本函数会通过迭代的方式,将参数里的每个成员都设置到新创建的列表对象中。

    因此,上面的list((1,3,5,7,9))得到的结果就是[1, 3, 5, 7, 9],list("13abc")得到的结果就是['1', '3', 'a', 'b', 'c'],list([3,4,5])得到的结果就是[3, 4, 5]。对于字符串参数而言,字符串里的每个字符都对应列表中的一个成员。

    具体的内部执行过程,可以参考上面的gdb的调试输出信息。list脚本函数在执行时,会先进入type_call,并通过PyType_GenericNew来创建一个新的列表对象。接着在list_init函数中对新列表进行初始化,也就是通过listextend函数先调整新列表的尺寸,再对参数进行迭代,从而将参数里的每个成员都设置到新创建的列表中。listextend函数的源码解析,可以参数下面 列表对象的extend方法 的内容。

列表对象所包含的方法:

    Python的列表对象本身也包含了各种与列表操作相关的方法,我们可以在list_methods数组中查看到这些方法(该数组定义在Objects/listobject.c文件中):

static PyMethodDef list_methods[] = {
    {"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST, getitem_doc},
    {"__reversed__",(PyCFunction)list_reversed, METH_NOARGS, reversed_doc},
    {"__sizeof__",  (PyCFunction)list_sizeof, METH_NOARGS, sizeof_doc},
    {"append",          (PyCFunction)listappend,  METH_O, append_doc},
    {"insert",          (PyCFunction)listinsert,  METH_VARARGS, insert_doc},
    {"extend",      (PyCFunction)listextend,  METH_O, extend_doc},
    {"pop",             (PyCFunction)listpop,     METH_VARARGS, pop_doc},
    {"remove",          (PyCFunction)listremove,  METH_O, remove_doc},
    {"index",           (PyCFunction)listindex,   METH_VARARGS, index_doc},
    {"count",           (PyCFunction)listcount,   METH_O, count_doc},
    {"reverse",         (PyCFunction)listreverse, METH_NOARGS, reverse_doc},
    {"sort",            (PyCFunction)listsort,    METH_VARARGS | METH_KEYWORDS, sort_doc},
    {NULL,              NULL}           /* sentinel */
};


    从上面list_methods数组中可以看到列表对象支持appendinsertextend之类的方法,还可以看到这些方法在执行时,会调用的底层C函数。例如:append方法对应的底层C函数为listappendinsert方法对应的底层C函数为listinsert等等。下面就对这些方法及它们会调用的这些C函数一一进行介绍。

列表对象的append方法:

    append方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list1 = [123, 'xyz', 'zara', 'abc'];
>>> list1.append(2009);
....................................................

Breakpoint 3, listappend (self=0xb7ca1e6c, v=0x822766c)
    at Objects/listobject.c:793
793	    if (app1(self, v) == 0)
(gdb) s
app1 (self=0xb7ca1e6c, v=0x822766c) at Objects/listobject.c:268
268	    Py_ssize_t n = PyList_GET_SIZE(self);
(gdb) c
Continuing.
>>> list1
[123, 'xyz', 'zara', 'abc', 2009]
>>> 


    上面的list1通过append方法,在列表尾部添加了一个2009的整数对象。该方法在执行时,内部会先进入listappend函数,再由app1这个C函数去完成具体的添加操作。listappendapp1这两个函数都定义在Objects/listobject.c文件中:

static int
app1(PyListObject *self, PyObject *v)
{
    // 先得到列表中的原尺寸信息。
    Py_ssize_t n = PyList_GET_SIZE(self);

    assert (v != NULL);
    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)
        return -1;

    Py_INCREF(v);
    // 将新成员添加到列表的尾部。
    PyList_SET_ITEM(self, n, v);
    return 0;
}

....................................................

static PyObject *
listappend(PyListObject *self, PyObject *v)
{
    // 通过上面的app1函数,将新成员对象v
    // 加入到列表的尾部。
    // 下面的self表示需要操作的列表。
    if (app1(self, v) == 0)
        Py_RETURN_NONE;
    return NULL;
}


列表对象的insert方法:

    insert方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2 = ['abc', 'def', 'xyz']
>>> list2.insert(1, 5)
....................................................

Breakpoint 4, listinsert (self=0xb7ca50a4, args=0xb7d3a92c)
    at Objects/listobject.c:783
783	    if (!PyArg_ParseTuple(args, "nO:insert", &i, &v))
(gdb) n
785	    if (ins1(self, i, v) == 0)
(gdb) s
ins1 (self=0xb7ca50a4, where=1, v=0x8207b0c) at Objects/listobject.c:225
225	    Py_ssize_t i, n = Py_SIZE(self);
(gdb) c
Continuing.
>>> list2
['abc', 5, 'def', 'xyz']
>>> 


    insert方法用于在指定的索引前面,插入某个成员对象。例如,上面的list2.insert(1, 5)执行后,就可以在原索引位置1即'def'成员的前面,插入一个整数5。

    该方法在内部会先进入listinsert函数,再由ins1函数去完成具体的插入操作。这两个C函数也都定义在Objects/listobject.c文件中:

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;
    }
    // 如果插入操作导致列表的尺寸,
    // 超出了有符号整数值的有效范围的话,
    // 就会抛出OverflowError的溢出错误。
    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)
        return -1;

    // 如果脚本传递过来的插入索引值小于0的话,
    // 就将插入索引值加上列表的原尺寸值,
    // 从而将其转为有效的索引值。
    if (where < 0) {
        where += n;
        // 如果加上原尺寸值后,还是小于0,
        // 则将插入索引值设置为0。
        if (where < 0)
            where = 0;
    }
    // 如果插入索引值超出了原尺寸的范围,
    // 则直接将新成员添加到列表的尾部。
    if (where > n)
        where = n;
    items = self->ob_item;
    // 先通过for循环将插入位置到原结束位置里的
    // 成员都往后移动一格。这样才能保证在最后
    // 执行完插入操作后,原来的成员对象不会丢失。
    for (i = n; --i >= where; )
        items[i+1] = items[i];
    Py_INCREF(v);
    // 将新成员对象设置到插入索引位置处。
    items[where] = v;
    return 0;
}

....................................................

static PyObject *
listinsert(PyListObject *self, PyObject *args)
{
    Py_ssize_t i;
    PyObject *v;
    // insert方法需要接受两个参数,
    // 第一个参数必须是整数对象,
    // 表示需要插入的索引值。
    // 第二个参数则是需要插入的新对象。
    if (!PyArg_ParseTuple(args, "nO:insert", &i, &v))
        return NULL;
    // 通过ins1函数去完成具体的插入操作。
    if (ins1(self, i, v) == 0)
        Py_RETURN_NONE;
    return NULL;
}


    从上面的代码中,可以看到,当插入索引值小于0时,该索引值会被加上列表的原尺寸值,从而将其转为有效的索引值。此外,当插入索引值超出了列表的原尺寸范围时,就会直接在列表的尾部追加新成员。如下例所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2
['abc', 5, 'def', 'xyz']
>>> list2.insert(-1, 'hello')
>>> list2
['abc', 5, 'def', 'hello', 'xyz']
>>> list2.insert(10, 'world')
>>> list2
['abc', 5, 'def', 'hello', 'xyz', 'world']
>>> 


    上例中,list2.insert(-1, 'hello')相当于list2.insert(3, 'hello')。因为-1小于0,因此,-1会被加上列表的原尺寸值4,结果就会在原索引3的位置即'xyz'的前面插入'hello'了。而list2.insert(10, 'world')中,由于10大于列表的原尺寸值4,因此,就会将'world'给追加到list2的尾部了。

列表对象的extend方法:

    extend方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2 = [123, 'xyz', 'zz']
>>> list2.extend(('abc','zlzl'));
....................................................

Breakpoint 5, listextend (self=0xb7c956c4, b=0xb7d3a92c)
    at Objects/listobject.c:812
812	    if (PyList_CheckExact(b) || PyTuple_CheckExact(b) || (PyObject *)self == b) {
....................................................
>>> list2
[123, 'xyz', 'zz', 'abc', 'zlzl']
>>> list2.extend('abc12345')
>>> list2
[123, 'xyz', 'zz', 'abc', 'zlzl', 'a', 'b', 'c', '1', '2', '3', '4', '5']
>>> list2.extend('abc12345', 1123)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: extend() takes exactly one argument (2 given)
>>> list2.extend(123)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>> 


    extend方法只能接受一个参数(否则会抛出TypeError: extend() takes exactly one argument...的错误),并且该参数必须是iterable(可迭代)的对象。该方法会对参数对象进行迭代,并将迭代得到的每个成员都添加到列表中,从而对列表进行扩充。

    例如:list2.extend(('abc','zlzl'))在执行时,就会将参数元组中的两个成员'abc'与'zlzl',依次迭代出来,并将它们都追加到list2的尾部。字符串在进行迭代时,字符串里的每个字符都对应为一个成员。

    extend方法在内部会通过listextend函数去完成具体的扩充列表的操作。该C函数同样定义在Objects/listobject.c文件中:

static PyObject *
listextend(PyListObject *self, PyObject *b)
{
    PyObject *it;      /* iter(v) */
    Py_ssize_t m;                  /* size of self */
    Py_ssize_t n;                  /* guess for size of b */
    Py_ssize_t mn;                 /* m + n */
    Py_ssize_t i;
    PyObject *(*iternext)(PyObject *);

    // 下面的self表示调用extend方法的列表对象,
    // b则是extend方法的参数对象。
    // 例如:list2.extend(('abc','zlzl'))执行时,
    // self就对应为list2,
    // 而b则对应为('abc','zlzl')这个元组参数,
    // 当b为列表或元组时,或者self == b时(如:
    // list2.extend(list2)执行时,self就等于b),
    // 这种情况下就调用PySequence_Fast函数对b
    // 进行处理,PySequence_Fast函数中,当b为
    // 列表或元组时,直接将b返回,
    // 除了增加了b的引用计数外,啥都没做。
    /* Special cases:
       1) lists and tuples which can use PySequence_Fast ops
       2) extending self to self requires making a copy first
    */
    if (PyList_CheckExact(b) || PyTuple_CheckExact(b) || (PyObject *)self == b) {
        PyObject **src, **dest;
        b = PySequence_Fast(b, "argument must be iterable");
        if (!b)
            return NULL;
        // 获取b的尺寸值,无论是列表对象还是
        // 元组对象,其尺寸(也就是包含的成员数)
        // 都存储在该对象的ob_size字段中。
        n = PySequence_Fast_GET_SIZE(b);
        // 如果b是空列表或空元组的话,
        // 就不需要进行扩充操作,则直接返回。
        if (n == 0) {
            /* short circuit when b is empty */
            Py_DECREF(b);
            Py_RETURN_NONE;
        }
        // 获取self的尺寸值。
        m = Py_SIZE(self);
        // 根据self与b的尺寸,对self
        // 的尺寸进行调整,让self可以
        // 容纳下两个集合里的所有成员。
        // (这里用集合来表示列表或元组)
        if (list_resize(self, m + n) == -1) {
            Py_DECREF(b);
            return NULL;
        }
        // 下面将b的ob_item数组指针设置到src,
        // 将self尾部扩充部分的起始位置设置到
        // dest,再通过for循环,就可以将
        // b里的所有成员都拷贝到self列表的
        // 尾部了。从而完成对self的扩充操作。
        // 无论是列表还是元组,其所包含的
        // 成员都存储在ob_item数组中。
        /* note that we may still have self == b here for the
         * situation a.extend(a), but the following code works
         * in that case too.  Just make sure to resize self
         * before calling PySequence_Fast_ITEMS.
         */
        /* populate the end of self with b's items */
        src = PySequence_Fast_ITEMS(b);
        dest = self->ob_item + m;
        for (i = 0; i < n; i++) {
            PyObject *o = src[i];
            Py_INCREF(o);
            dest[i] = o;
        }
        Py_DECREF(b);
        Py_RETURN_NONE;
    }

    // 如果b是其他类型的可迭代对象(如字符串)
    // 的话,则先获取b的迭代器。
    it = PyObject_GetIter(b);
    if (it == NULL)
        return NULL;
    iternext = *it->ob_type->tp_iternext;

    /* Guess a result list size. */
    // 获取b的尺寸值。
    n = _PyObject_LengthHint(b, 8);
    ................................................
    // 获取self的尺寸值。
    m = Py_SIZE(self);
    // 将b的尺寸加上self的尺寸,
    // 以此来调整self的尺寸空间。
    mn = m + n;
    if (mn >= m) {
        /* Make room. */
        if (list_resize(self, mn) == -1)
            goto error;
        /* Make the list sane again. */
        Py_SIZE(self) = m;
    }
    /* Else m + n overflowed; on the chance that n lied, and there really
     * is enough room, ignore it.  If n was telling the truth, we'll
     * eventually run out of memory during the loop.
     */

    // 通过循环迭代的方式,将b里的
    // 所有成员都设置到self的尾部。
    // 从而完成对self列表的扩充操作。
    // 例如:list2.extend('abc')在执行时,
    // extend方法会依次将'abc'里的三个字符
    // 'a','b','c'都迭代出来,并将它们都
    // 追加到list2的尾部。
    // 如果list2是[1, 2, 3]的话,
    // 扩充后的结果就是[1, 2, 3, 'a', 'b', 'c']。
    /* Run iterator to exhaustion. */
    for (;;) {
        PyObject *item = iternext(it);
        ............................................
        if (Py_SIZE(self) < self->allocated) {
            /* steals ref */
            PyList_SET_ITEM(self, Py_SIZE(self), item);
            ++Py_SIZE(self);
        }
        ............................................
    }

    ................................................
}


列表对象的pop方法:

    pop方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2
['abc', 5, 'def', 'xyz']
>>> list2.pop()
....................................................

Breakpoint 3, listpop (self=0xb7c956c4, args=0xb7dcc034)
    at Objects/listobject.c:929
929	    Py_ssize_t i = -1;
....................................................
'xyz'
>>> list2
['abc', 5, 'def']
>>> list2.pop(1)
5
>>> list2
['abc', 'def']
>>> 


    pop方法最多只能接受一个参数,当没提供任何参数时,会将列表中的最后一个成员弹出,弹出的含义就是将该成员作为结果返回,同时将其从列表里删除。例如,上面的list2.pop()执行后,就将最后一个成员'xyz'返回,同时将其从list2中删除掉。

    如果提供了整数参数的话,就将列表里该整数对应的索引位置处的成员给弹出。例如,上面的list2.pop(1)执行时,就会将list2中索引值为1的成员给弹出来。

    pop方法执行时,内部会通过listpop函数去完成具体的弹出操作,这个C函数定义在Objects/listobject.c文件中:

static PyObject *
listpop(PyListObject *self, PyObject *args)
{
    Py_ssize_t i = -1;
    PyObject *v;
    int status;

    // pop方法可以接受一个可选的整数参数,
    // 作为需要弹出的成员的列表索引值。
    // 当没提供任何参数时,下面的i就会是-1,
    // -1是i在上面设置过的初始值,当i为-1
    // 时,后面会将-1再加上列表的尺寸,从而
    // 将其转为列表的最后一个成员的索引值。
    // 因此,在没提供任何参数时,
    // 就是将列表的最后一个成员给弹出来。
    if (!PyArg_ParseTuple(args, "|n:pop", &i))
        return NULL;

    // 如果是空列表,则会抛出IndexError的错误。
    if (Py_SIZE(self) == 0) {
        /* Special-case most common failure cause */
        PyErr_SetString(PyExc_IndexError, "pop from empty list");
        return NULL;
    }
    // 当i小于0时,也就是索引值小于0时,
    // 会将索引值加上列表的尺寸,
    // 从而将其转为有效的索引值。
    // 由于i的默认初始值是-1,因此,
    // list2.pop(-1)与list2.pop()执行的
    // 效果是一样的,都是将列表的
    // 最后一个成员给弹出来。
    if (i < 0)
        i += Py_SIZE(self);
    // 如果索引值经过处理后,还是超出了
    // 列表尺寸的有效范围的话,就会
    // 抛出IndexError的错误。
    if (i < 0 || i >= Py_SIZE(self)) {
        PyErr_SetString(PyExc_IndexError, "pop index out of range");
        return NULL;
    }
    // 将索引i对应的列表成员,设置到变量v中,
    // 最后会将v作为结果返回。
    v = self->ob_item[i];
    // 如果是弹出最后一个成员的话,
    // 则直接通过list_resize函数,将列表的
    // 尺寸大小减一即可将最后一个成员给
    // 删除掉,最后再将v返回,就可以完成
    // 弹出操作了。
    if (i == Py_SIZE(self) - 1) {
        status = list_resize(self, Py_SIZE(self) - 1);
        assert(status >= 0);
        return v; /* and v now owns the reference the list had */
    }
    // 如果不是最后一个成员的话,
    // 就需要通过list_ass_slice函数来完成
    // 删除操作,再将v作为结果返回。
    // list_ass_slice函数的源代码,
    // 已经在上一篇文章中详细的讲解过了。
    Py_INCREF(v);
    status = list_ass_slice(self, i, i+1, (PyObject *)NULL);
    assert(status >= 0);
    /* Use status, so that in a release build compilers don't
     * complain about the unused name.
     */
    (void) status;

    return v;
}


列表对象的remove方法:

    remove方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2 = ['abc', 'def', 'xyz']
>>> list2.remove('def')
....................................................

Breakpoint 4, listremove (self=0xb7c956c4, v=0xb7ca0268)
    at Objects/listobject.c:2341
2341	    for (i = 0; i < Py_SIZE(self); i++) {
....................................................
>>> list2
['abc', 'xyz']
>>> list3 = ['abc', 'def', 'xyz', 'def']
>>> list3.remove('def')
>>> list3
['abc', 'xyz', 'def']
>>> 


    remove方法会将参数对象在列表中进行查找,当找到值相等的列表成员时,就将该成员给移除掉。例如,上面的list2.remove('def')执行后,就将list2里的'def'给移除掉了。

    此外,remove方法只会将找到的第一个成员给移除掉,之后的成员不会受到影响。例如,当上面的list3为['abc', 'def', 'xyz', 'def']时,在执行完list3.remove('def')脚本后,只会将第一个找到的'def'给移除掉,最后一个'def'则不受影响。

    remove方法在内部会通过listremove函数去完成具体的移除操作。该函数也定义在Objects/listobject.c文件中:

static PyObject *
listremove(PyListObject *self, PyObject *v)
{
    Py_ssize_t i;

    // 通过for循环,从索引值0开始,
    // 将列表中的成员依次提取出来,
    // 并将这些成员与参数对象v进行比较。
    // 当找到第一个值相等的成员时,
    // 就通过list_ass_slice函数将该成员
    // 从列表中给移除掉。
    // 找到并删除成员后,会直接返回,
    // 不会继续往下查找。因此,之后的
    // 成员不会受到影响。
    for (i = 0; i < Py_SIZE(self); i++) {
        int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
        if (cmp > 0) {
            if (list_ass_slice(self, i, i+1,
                               (PyObject *)NULL) == 0)
                Py_RETURN_NONE;
            return NULL;
        }
        else if (cmp < 0)
            return NULL;
    }
    // 如果没找到符合条件的成员,
    // 则会抛出ValueError的错误。
    PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list");
    return NULL;
}


列表对象的index方法:

    index方法的使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2 = [123, 'xyz', 'zz', 'a', 'b', 'c', '1']
>>> list2.index('a')
....................................................

Breakpoint 5, listindex (self=0xb7ca1b5c, args=0xb7c9ff4c)
    at Objects/listobject.c:2278
2278	    Py_ssize_t i, start=0, stop=Py_SIZE(self);
....................................................
3
>>> list2.index('a', 2, 5)
3
>>> list2.index('a', 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'a' is not in list
>>> 


    index方法会使用参数对象,在列表中查找成员,当找到与参数对象的值相等的成员时,就将该成员对应的列表索引值作为结果返回。

    index方法还可以接受两个额外的可选参数,例如:上面的list2.index('a', 2, 5),这里的2和5就表示在列表的索引2到索引5(不包括5在内)的片段中,搜索'a'。

    如果index方法找不到符合条件的成员时,就会抛出类似 ValueError: 'a' is not in list 的错误。

    index方法会调用的底层C函数为listindex,该函数定义在Objects/listobject.c文件中:

static PyObject *
listindex(PyListObject *self, PyObject *args)
{
    Py_ssize_t i, start=0, stop=Py_SIZE(self);
    PyObject *v, *format_tuple, *err_string;
    static PyObject *err_format = NULL;

    // 将需要比较的参数对象设置到v,
    // 如果提供了可选参数,则将可选
    // 参数设置到start与stop中,
    // 作为需要进行搜索的列表片段的
    // 起始与结束位置。
    // 如果没提供可选参数的话,
    // start的默认初始值为0,
    // stop的默认初始值则为列表的总长度。
    // 后面就会在start到stop的列表索引范围内
    // (不包括stop在内)对v进行搜索。
    if (!PyArg_ParseTuple(args, "O|O&O&:index", &v,
                                _PyEval_SliceIndex, &start,
                                _PyEval_SliceIndex, &stop))
        return NULL;
    // 当start小于0时,就将其加上列表的
    // 尺寸值,从而将其转为有效的索引值。
    if (start < 0) {
        start += Py_SIZE(self);
        if (start < 0)
            start = 0;
    }
    // 同理,将小于0的stop转为有效的索引值。
    if (stop < 0) {
        stop += Py_SIZE(self);
        if (stop < 0)
            stop = 0;
    }
    // 通过for循环,将列表的start到stop
    // (不包括stop在内)的范围里的成员与v进行比较。
    // 如果从中找到了值相等的成员时,就将
    // 该成员对应的列表索引值作为结果返回。
    for (i = start; i < stop && i < Py_SIZE(self); i++) {
        int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
        if (cmp > 0)
            return PyInt_FromSsize_t(i);
        else if (cmp < 0)
            return NULL;
    }
    // 如果搜索不到符合条件的成员,
    // 则会抛出 "... is not in list"的错误。
    if (err_format == NULL) {
        err_format = PyString_FromString("%r is not in list");
        if (err_format == NULL)
            return NULL;
    }
    ................................................
}


列表对象的count方法:

    count方法的具体使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2 = [1, 3, 4, 4, 4, 5, 6, 8]
>>> list2.count(4)
....................................................

Breakpoint 7, listcount (self=0xb7ca1aec, v=0x8207b20)
    at Objects/listobject.c:2323
2323	    Py_ssize_t count = 0;
....................................................
3
>>> 


    可以看到,count方法会将列表中与参数对象的值相等的成员的个数给统计出来。例如,上面的list2列表里包含了三个4,因此,list2.count(4)脚本执行后,返回的结果就是3

    count方法对应的底层C函数为listcount,该函数也定义在Objects/listobject.c文件中:

static PyObject *
listcount(PyListObject *self, PyObject *v)
{
    Py_ssize_t count = 0;
    Py_ssize_t i;

    // 这里的self表示需要进行搜索的列表,
    // v则表示需要进行统计的参数对象。
    // 通过for循环,从索引值0开始,
    // 将列表中的所有成员都与v进行比较。
    // 每当找到一个与v的值相等的成员时,
    // 就将count计数器的值加一。
    // 这样就可以将符合条件的成员个数
    // 给统计出来了。
    for (i = 0; i < Py_SIZE(self); i++) {
        int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
        if (cmp > 0)
            count++;
        else if (cmp < 0)
            return NULL;
    }
    // 将count作为结果返回。
    // 此外,由于count的默认初始值为0,
    // 因此,当没有找到符合条件的成员时。
    // 就会返回0。
    return PyInt_FromSsize_t(count);
}


列表对象的reverse方法:

    reverse方法的具体使用,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2
['abc', 1, 2, 3, 4, 555, 'xyz']
>>> list2.reverse()
....................................................

Breakpoint 8, listreverse (self=0xb7ca1b5c) at Objects/listobject.c:2231
2231	    if (Py_SIZE(self) > 1)
....................................................
>>> list2
['xyz', 555, 4, 3, 2, 1, 'abc']
>>> 


    从上面的输出中可以看到,reverse方法其实就是将列表里的所有成员的位置倒转过来。因此,上面的['abc', 1, 2, 3, 4, 555, 'xyz']的列表,经过reverse倒转后,就变为['xyz', 555, 4, 3, 2, 1, 'abc']了。

    reverse方法对应的底层C函数为listreverse,该函数同样定义在Objects/listobject.c文件中:

/* Reverse a slice of a list in place, from lo up to (exclusive) hi. */
static void
reverse_slice(PyObject **lo, PyObject **hi)
{
    assert(lo && hi);

    --hi;
    // lo与hi都是指向列表成员的指针。
    // 下面通过while循环,将lo到hi的成员,
    // 两两进行交换。
    // 例如,当lo最开始指向列表的第一个成员,
    // 并且hi最开始指向最后一个成员时,
    // 列表的第一个成员就会与最后一个成员
    // 进行交换。
    // 而第二个成员则会与倒数第二个
    // 成员进行交换。
    // 以此类推,这样就将列表中的成员
    // 的位置给倒转过来了。
    while (lo < hi) {
        PyObject *t = *lo;
        *lo = *hi;
        *hi = t;
        ++lo;
        --hi;
    }
}

....................................................

static PyObject *
listreverse(PyListObject *self)
{
    // 如果列表中包含的成员数大于1的话,
    // 就会通过上面的reverse_slice函数来
    // 对列表中的成员进行倒转操作。
    // 当列表中只包含一个成员时,或者没有
    // 成员(列表为空)时,就没必要进行倒转操作了。
    if (Py_SIZE(self) > 1)
        reverse_slice(self->ob_item, self->ob_item + Py_SIZE(self));
    Py_RETURN_NONE;
}


列表对象的sort方法:

    sort方法可以对列表里的成员进行排序。当没提供任何参数时,该方法会将列表中的成员以默认方式进行从小到大的排序,如下所示:

[email protected]:~$ gdb -q python
....................................................
>>> list2 = [3, 5, 8, 10, 4, 6, 9]
>>> list2
[3, 5, 8, 10, 4, 6, 9]
>>> list2.sort()
....................................................
Breakpoint 9, listsort (self=0xb7ca1aec, args=0xb7dcc034, kwds=0x0)
    at Objects/listobject.c:2052
2052	    PyObject *compare = NULL;
....................................................
>>> list2
[3, 4, 5, 6, 8, 9, 10]
>>> 


    sort方法最终会通过listsort这个底层C函数去完成具体的排序操作,该函数定义在Objects/listobject.c文件中:

static PyObject *
listsort(PyListObject *self, PyObject *args, PyObject *kwds)
{
    ................................................
    // sort函数有三个可选参数,
    // 第一个参数用来设置compare脚本函数,
    // 第二个参数用来设置keyfunc脚本函数,
    // 第三个参数用来设置reverse。
    // 例如:

    // >>> list2
    // [3, 5, 8, 10, 4, 6, 9]
    // >>> def mycmp(a, b):
    // ...   if(a < b):
    // ...     return 1
    // ...   elif(a >= b):
    // ...     return -1
    // ... 
    // >>> list2.sort(mycmp)
    // >>> list2
    // [10, 9, 8, 6, 5, 4, 3]

    // 上面在对list2执行sort方法时,传递了
    // 一个mycmp参数,这样在排序时就会使用
    // 用户自定义的mycmp来对列表成员进行比较了,
    // 并根据mycmp的比较结果来排序。
    // 由于mycmp中,a < b时返回的是1,
    // 因此,经过mycmp比较后,越小的成员反而
    // 排在后面了。
    // 此外我们还可以使用cmp名值对来设置compare
    // 脚本函数。
    // 即list2.sort(mycmp)等效于
    // list2.sort(cmp = mycmp)。

    // 如果提供了第二个keyfunc参数,
    // 则进行比较前,会先将原列表成员经过
    // keyfunc转换,再进行比较。
    // 例如:

    // >>> def mykey(x):
    // ...   if(x == 5):
    // ...     return 1
    // ...   else:
    // ...     return x
    // ... 
    // >>> list2.sort(mycmp, mykey)
    // >>> list2
    // [10, 9, 8, 6, 4, 3, 5]

    // 上面在用mycmp比较成员之前,会先
    // 将成员经过mykey转换,
    // 5会被转为1,再进行比较。
    // 因此,5就被排在最后了。
    // 同样的,我们也可以使用key名值对
    // 来设置keyfunc脚本函数。
    // 即list2.sort(mycmp, mykey)等效于
    // list2.sort(mycmp, key = mykey),
    // 还等效于
    // list2.sort(cmp = mycmp, key = mykey)。

    // 如果提供了第三个参数的话,
    // 则会使用第三个参数来设置reverse,
    // reverse可以用来设置是否需要对结果
    // 再进行倒序处理。
    // 例如:

    // >>> list2.sort(mycmp, mykey, True)
    // >>> list2
    // [5, 3, 4, 6, 8, 9, 10]

    // 上面将reverse设置为True,表示
    // 需要进行倒序处理,因此,sort
    // 在经过mykey和mycmp处理后,
    // 最后还会将整个结果倒转过来。
    // 只要reverse不为0,都会被当作True,
    // 因此,list2.sort(mycmp, mykey, 100)与
    // list2.sort(mycmp, mykey, -1),得到
    // 的结果都与list2.sort(mycmp, mykey, True)
    // 是一样的。
    // 当reverse为0或False,或者不提供reverse
    // 参数时,则不会对结果进行倒序处理。
    // 此外,同样可以用reverse名值对来设置
    // reverse的值。
    // 因此,list2.sort(mycmp, mykey, True)
    // 等效于
    // list2.sort(mycmp, mykey, reverse = True)
    static char *kwlist[] = {"cmp", "key", "reverse", 0};

    assert(self != NULL);
    assert (PyList_Check(self));
    if (args != NULL) {
        if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:sort",
            kwlist, &compare, &keyfunc, &reverse))
            return NULL;
    }
    ................................................
}


结束语:

    以上就是和列表相关的脚本函数。下一篇将介绍Tuple元组相关的内容。

    OK,休息,休息一下 o(∩_∩)o~~

    生命就是一个克服惰性的过程,人生就是运动,就是奋斗,就是创造。

——  unknown
 
上下篇

下一篇: Python元组类型及相关函数

上一篇: Python列表类型

相关文章

Python列表类型

Python的安装与使用

Python随机数函数

Python字符串类型

Python基本的操作运算符

Python用户自定义函数