Cet article vous présente principalement les informations pertinentes sur l'abonnement aux tranches de séquence dans Python L'article le présente en détail à travers un exemple de code, qui a une certaine valeur de référence et d'apprentissage pour tous les amis qui en ont besoin. jetez un œil ensemble ci-dessous.
Préface
En python, le découpage est une syntaxe fréquemment utilisée, qu'il s'agisse d'un tuple, d'une liste ou de String, la syntaxe générale est :
sequence[ilow:ihigh:step] # ihigh
, step peut être vide ; par souci de simplicité et de facilité de compréhension, l'utilisation de step est temporairement exclue de la considération
Donnons une démonstration simple d'utilisation
sequence = [1,2,3,4,5] sequence [ilow:ihigh] # 从ilow开始到ihigh-1结束 sequence [ilow:] # 从ilow开始直到末尾 sequence [:ihigh] # 从头部开始直到ihigh结束 sequence [:] # 复制整个列表
La syntaxe est très concise et facile à comprendre. facile à utiliser dans notre utilisation quotidienne. Mais je crois que lorsque nous utilisons cette syntaxe de découpage, nous suivrons habituellement certaines règles :
ilow et ihigh sont tous deux plus petits que la longueur de la séquence
ilow < ihigh
Parce que dans la plupart des cas, ce n'est qu'en suivant les règles ci-dessus que nous pouvons obtenir les résultats que nous attendions ! et si je ne le suis pas ? Le découpage va comment ?
Peu importe que nous utilisions des tuples, des listes ou des chaînes, lorsque nous voulons obtenir un élément, nous utiliserons la syntaxe suivante :
sequence = [1,2,3,4,5] print sequence[1] # 输出2 print sequence[2] # 输出3
Appelons les 1 et 2 qui apparaissent au-dessus des indices. Qu'il s'agisse d'un tuple, d'une liste ou d'une chaîne, nous pouvons utiliser l'indice pour obtenir la valeur correspondante, mais si le l'indice dépasse la longueur de l'objet, alors une exception Index (IndexError) sera déclenchée
sequence = [1,2,3,4,5] print sequence[15] ### 输出 ### Traceback (most recent call last): File "test.py", line 2, in <module> print a[20] IndexError: list index out of range
Alors qu'en est-il du découpage ? Les deux syntaxes sont très similaires. et ihigh valent respectivement 10 et 20, alors le résultat est Que diriez-vous de ça
La scène réapparaît
# version: python2.7 a = [1, 2, 3, 5] print a[10:20] # 结果会报异常吗?
En voyant 10 et 20, il dépasse complètement la longueur de la séquence a. En raison du code précédent ou de l'expérience précédente, nous pensons toujours que cela provoquera certainement une IndexError. Ensuite, nous ouvrons le terminal pour le tester :
>>> a = [1, 2, 3, 5] >>> print a[10:20] []
Le résultat est en fait : [], ce qui semble un peu intéressant. Seules les listes peuvent faire cela, qu'en est-il des chaînes, qu'en est-il des tuples ?
>>> s = '23123123123' >>> print s[400:2000] '' >>> t = (1, 2, 3,4) >>> print t[200: 1000] ()
Les résultats sont similaires à ceux de la liste, renvoyant leurs propres résultats vides.
Nous avons versé des larmes lorsque nous avons vu les résultats au lieu de renvoyer une IndexError. , nous sommes directement revenus vides. Cela nous a fait penser que la syntaxe est en fait similaire, les choses derrière elle sont définitivement différentes, alors essayons d'expliquer les résultats ensemble
Analyse des principes<🎜. >
<. 🎜>
############# 切片 ################ [root@iZ23pynfq19Z ~]# cat test.py a = [11,2,3,4] print a[20:30] #结果: [root@iZ23pynfq19Z ~]# python -m dis test.py 1 0 LOAD_CONST 0 (11) 3 LOAD_CONST 1 (2) 6 LOAD_CONST 2 (3) 9 LOAD_CONST 3 (4) 12 BUILD_LIST 4 15 STORE_NAME 0 (a) 2 18 LOAD_NAME 0 (a) 21 LOAD_CONST 4 (20) 24 LOAD_CONST 5 (30) 27 SLICE+3 28 PRINT_ITEM 29 PRINT_NEWLINE 30 LOAD_CONST 6 (None) 33 RETURN_VALUE ############# 单下标取值 ################ [root@gitlab ~]# cat test2.py a = [11,2,3,4] print a[20] #结果: [root@gitlab ~]# python -m dis test2.py 1 0 LOAD_CONST 0 (11) 3 LOAD_CONST 1 (2) 6 LOAD_CONST 2 (3) 9 LOAD_CONST 3 (4) 12 BUILD_LIST 4 15 STORE_NAME 0 (a) 2 18 LOAD_NAME 0 (a) 21 LOAD_CONST 4 (20) 24 BINARY_SUBSCR 25 PRINT_ITEM 26 PRINT_NEWLINE 27 LOAD_CONST 5 (None) 30 RETURN_VALUE
code, et dis affiche ces bytecodes de manière plus impressionnante, nous permettant de voir le processus d'exécution. Ce qui suit est une explication des colonnes de sortie de dis : <🎜. >
La première colonne est Les chiffres sont les numéros de ligne du code source d'origine.
Bien que le code ci-dessus soit un peu long, les endroits clés ont été commentés, et nous n'avons qu'à faire attention à ces endroits. Comme ci-dessus, nous savons que nous finirons par exécuter
/*取自: python2.7 python/ceval.c */ // 第一步: PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) { .... // 省略n行代码 TARGET_WITH_IMPL_NOARG(SLICE, _slice) TARGET_WITH_IMPL_NOARG(SLICE_1, _slice) TARGET_WITH_IMPL_NOARG(SLICE_2, _slice) TARGET_WITH_IMPL_NOARG(SLICE_3, _slice) _slice: { if ((opcode-SLICE) & 2) w = POP(); else w = NULL; if ((opcode-SLICE) & 1) v = POP(); else v = NULL; u = TOP(); x = apply_slice(u, v, w); // 取出v: ilow, w: ihigh, 然后调用apply_slice Py_DECREF(u); Py_XDECREF(v); Py_XDECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); break; } .... // 省略n行代码 } // 第二步: apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ { PyTypeObject *tp = u->ob_type; PySequenceMethods *sq = tp->tp_as_sequence; if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { // v,w的类型检查,要整型/长整型对象 Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; if (!_PyEval_SliceIndex(v, &ilow)) // 将v对象再做检查, 并将其值转换出来,存给ilow return NULL; if (!_PyEval_SliceIndex(w, &ihigh)) // 同上 return NULL; return PySequence_GetSlice(u, ilow, ihigh); // 获取u对象对应的切片函数 } else { PyObject *slice = PySlice_New(v, w, NULL); if (slice != NULL) { PyObject *res = PyObject_GetItem(u, slice); Py_DECREF(slice); return res; } else return NULL; } // 第三步: PySequence_GetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) { PySequenceMethods *m; PyMappingMethods *mp; if (!s) return null_error(); m = s->ob_type->tp_as_sequence; if (m && m->sq_slice) { if (i1 < 0 || i2 < 0) { if (m->sq_length) { // 先做个简单的初始化, 如果左右下表小于, 将其加上sequence长度使其归为0 Py_ssize_t l = (*m->sq_length)(s); if (l < 0) return NULL; if (i1 < 0) i1 += l; if (i2 < 0) i2 += l; } } // 真正调用对象的sq_slice函数, 来执行切片的操作 return m->sq_slice(s, i1, i2); } else if ((mp = s->ob_type->tp_as_mapping) && mp->mp_subscript) { PyObject *res; PyObject *slice = _PySlice_FromIndices(i1, i2); if (!slice) return NULL; res = mp->mp_subscript(s, slice); Py_DECREF(slice); return res; } return type_error("'%.200s' object is unsliceable", s);
m->sq_slice(s, i1, i2)
Parce qu'ils sont trois, les implémentations des fonctions sont à peu près les mêmes. , nous n'avons donc besoin d'en analyser qu'un. Ce qui suit est une analyse de la fonction de découpage de la liste :
// 字符串对象 StringObject.c: (ssizessizeargfunc)string_slice, /*sq_slice*/ // 列表对象 ListObject.c: (ssizessizeargfunc)list_slice, /* sq_slice */ // 元组 TupleObject.c: (ssizessizeargfunc)tupleslice, /* sq_slice */
/* 取自ListObject.c */ static PyObject * list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh) { PyListObject *np; PyObject **src, **dest; Py_ssize_t i, len; if (ilow < 0) ilow = 0; else if (ilow > Py_SIZE(a)) // 如果ilow大于a长度, 那么重新赋值为a的长度 ilow = Py_SIZE(a); if (ihigh < ilow) ihigh = ilow; else if (ihigh > Py_SIZE(a)) // 如果ihigh大于a长度, 那么重新赋值为a的长度 ihigh = Py_SIZE(a); len = ihigh - ilow; np = (PyListObject *) PyList_New(len); // 创建一个ihigh - ilow的新列表对象 if (np == NULL) return NULL; src = a->ob_item + ilow; dest = np->ob_item; for (i = 0; i < len; i++) { // 将a处于该范围内的成员, 添加到新列表对象 PyObject *v = src[i]; Py_INCREF(v); dest[i] = v; } return (PyObject *)np; }
Comme le montre la fonction de découpage correspondant à la fonction sq_slice ci-dessus, si lors de l'utilisation du découpage, les indices gauche et droit sont supérieurs à la longueur de la séquence, ils seront réaffectés à la longueur de la séquence, donc notre découpage initial : print a[10:20]
, ce qui s'exécute réellement est : print a4:4
. Grâce à cette analyse, vous ne serez plus confus lorsque vous rencontrerez une tranche dont l'indice est supérieur à la longueur de l'objet~
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!