页面导航:
英文教程的下载地址:
本篇文章是根据英文教程《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
>>>
|
cmp是
bltinmodule(内建模块)里的函数,对应的底层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_EQ、
Py_LT及
Py_GT。在最后的
for循环里,会依次将这三个
op值传递给
try_rich_compare_bool函数,如果哪个
op值返回
1,则将对应的
outcome值作为结果返回。
例如:当传递
Py_EQ时,如果
try_rich_compare_bool返回
1的话,就说明v与w相等,结果就会将对应的
outcome即
0返回。
如果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_iter与
listiter_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在进行迭代比较后,是将值最小的成员对象给获取出来。
从上面的调试中可以看到,
min与
max在内部最终都是通过
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数组中可以看到列表对象支持
append,
insert,
extend之类的方法,还可以看到这些方法在执行时,会调用的底层C函数。例如:
append方法对应的底层C函数为
listappend,
insert方法对应的底层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函数去完成具体的添加操作。
listappend与
app1这两个函数都定义在
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