本文主要介绍的关于Python切片赋值的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍:
昨天有同学问了我这么个问题:
1
2
3
|
t = [ 1 , 2 , 3 ] t[ 1 : 1 ] = [ 7 ] # 感谢@一往直前 的疑问,之前写为 t[1:1] = 7了 print t # 输出 [1, 7, 2, 3] |
这个问题之前还真没遇到过,有谁会对列表这么进行赋值吗?不过对于这个输出结果的原因确实值得去再了解下,毕竟之前也看过《Python源码分析》。(题外话:据说最近有大牛在写新的版本)
想着今天有空看看Python的源码,去了解下原理是什么。
注:我本地之前下载的是Python2.7.6的代码,直接看的这个。
在Objects/listobject.c中有一个 PyList_SetSlice 函数,是这么写的:
1
2
3
4
5
6
7
8
9
|
int PyList_SetSlice(PyObject * a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject * v) { if (!PyList_Check(a)) { PyErr_BadInternalCall(); return - 1 ; } return list_ass_slice((PyListObject * )a, ilow, ihigh, v); } |
有用的一句就是 list_ass_slice ,那么再来看看这个函数的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
static int list_ass_slice(PyListObject * a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject * v) { / * Because [X]DECREF can recursively invoke list operations on this list , we must postpone all [X]DECREF activity until after the list is back in its canonical shape. Therefore we must allocate an additional array, 'recycle' , into which we temporarily copy the items that are deleted from the list . : - ( * / PyObject * recycle_on_stack[ 8 ]; PyObject * * recycle = recycle_on_stack; / * will allocate more if needed * / PyObject * * item; PyObject * * vitem = NULL; PyObject * v_as_SF = NULL; / * PySequence_Fast(v) * / Py_ssize_t n; / * # of elements in replacement list */ Py_ssize_t norig; / * # of elements in list getting replaced */ Py_ssize_t d; / * Change in size * / Py_ssize_t k; size_t s; int result = - 1 ; / * guilty until proved innocent * / #define b ((PyListObject *)v) if (v = = NULL) n = 0 ; else { if (a = = b) { / * Special case "a[i:j] = a" - - copy b first * / v = list_slice(b, 0 , Py_SIZE(b)); if (v = = NULL) return result; result = list_ass_slice(a, ilow, ihigh, v); Py_DECREF(v); return result; } v_as_SF = PySequence_Fast(v, "can only assign an iterable" ); if (v_as_SF = = NULL) goto Error; / * the5fire注: 要赋值的长度n * / n = PySequence_Fast_GET_SIZE(v_as_SF); vitem = PySequence_Fast_ITEMS(v_as_SF); } if (ilow < 0 ) ilow = 0 ; else if (ilow > Py_SIZE(a)) ilow = Py_SIZE(a); if (ihigh < ilow) ihigh = ilow; else if (ihigh > Py_SIZE(a)) ihigh = Py_SIZE(a); norig = ihigh - ilow; assert (norig > = 0 ); d = n - norig; if (Py_SIZE(a) + d = = 0 ) { Py_XDECREF(v_as_SF); return list_clear(a); } item = a - >ob_item; / * recycle the items that we are about to remove * / s = norig * sizeof(PyObject * ); if (s > sizeof(recycle_on_stack)) { recycle = (PyObject * * )PyMem_MALLOC(s); if (recycle = = NULL) { PyErr_NoMemory(); goto Error; } } memcpy(recycle, &item[ilow], s); if (d < 0 ) { / * Delete - d items * / memmove(&item[ihigh + d], &item[ihigh], (Py_SIZE(a) - ihigh) * sizeof(PyObject * )); list_resize(a, Py_SIZE(a) + d); item = a - >ob_item; } else if (d > 0 ) { / * Insert d items * / k = Py_SIZE(a); if (list_resize(a, k + d) < 0 ) goto Error; item = a - >ob_item; printf( "关键点\n" ); / * the5fire注: 把 list 对应切片后一位的值之后的所有内容向后移动所赋值的大小 按照上面的python代码这里就是 原理的t: | 1 | 2 | 3 | 后移一位,因为 len ([ 7 ]) = 1 | 1 |空| 2 | 3 |把后两个移位 * / memmove(&item[ihigh + d], &item[ihigh], (k - ihigh) * sizeof(PyObject * )); } / * the5fire注: 赋值操作,即把[ 7 ]赋值到t里的对应位置上 ilow是 1 , n是 1 * / for (k = 0 ; k < n; k + + , ilow + + ) { PyObject * w = vitem[k]; Py_XINCREF(w); item[ilow] = w; } for (k = norig - 1 ; k > = 0 ; - - k) Py_XDECREF(recycle[k]); result = 0 ; Error: if (recycle ! = recycle_on_stack) PyMem_FREE(recycle); Py_XDECREF(v_as_SF); return result; #undef b } |
看了知乎,stackoverflow上的解答,发现源码还是最好的解释。上述关键位置已经加了注释,应该很好理解。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://www.the5fire.com/python-slice-assignment-analyse-souce-code.html