Dieser Artikel stellt Ihnen hauptsächlich die relevanten Informationen zum Sequence-Slice-Abonnement in Python vor. Der Artikel stellt es detailliert anhand von Beispielcode vor, der für alle Freunde, die ihn benötigen, einen gewissen Referenz- und Lernwert hat Schauen Sie sich das unten zusammen an.
Vorwort
In Python ist Slicing eine häufig verwendete Syntax, egal ob es sich um ein Tupel, eine Liste oder handelt Zeichenfolge, die allgemeine Syntax lautet:
sequence[ilow:ihigh:step] # ihigh
, Schritt kann der Einfachheit halber und zum leichteren Verständnis leer sein; die Verwendung von Schritt wird vorübergehend von der Betrachtung ausgeschlossen
Lassen Sie uns eine einfache Demonstration der Verwendung geben
sequence = [1,2,3,4,5] sequence [ilow:ihigh] # 从ilow开始到ihigh-1结束 sequence [ilow:] # 从ilow开始直到末尾 sequence [:ihigh] # 从头部开始直到ihigh结束 sequence [:] # 复制整个列表
Die Syntax ist sehr prägnant und leicht zu verstehen einfach in unserem täglichen Gebrauch zu verwenden. Ich glaube jedoch, dass wir bei der Verwendung dieser Slicing-Syntax normalerweise einige Regeln befolgen:
ilow und ihigh sind beide kleiner als die Länge der Sequenz
ilow < ihigh
Denn in den meisten Fällen können wir die erwarteten Ergebnisse erzielen Was passiert, wenn ich dem nicht folge? Wie geht das?
Egal, ob wir Tupel, Listen oder Strings verwenden, wenn wir ein Element erhalten möchten, verwenden wir die folgende Syntax:
sequence = [1,2,3,4,5] print sequence[1] # 输出2 print sequence[2] # 输出3
Die oben angezeigten 1 und 2 werden als Indizes bezeichnet. Unabhängig davon, ob es sich um ein Tupel, eine Liste oder eine Zeichenfolge handelt, können wir den Index verwenden, um den entsprechenden Wert zu erhalten Der Index überschreitet die Länge des Objekts, dann wird eine Indexausnahme (IndexError) ausgelöst
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
Was ist also mit dem Slicing? Angenommen, mein ilow und ihigh 10 bzw. 20 sind, dann ist das Ergebnis „Wie wäre es damit?“ >
Wenn wir 10 und 20 sehen, überschreitet es die Länge der Sequenz a vollständig. Aufgrund des vorherigen Codes oder der vorherigen Erfahrung haben wir immer das Gefühl, dass dies definitiv einen IndexError verursachen wird. Dann öffnen wir das Terminal, um es zu testen:
# version: python2.7 a = [1, 2, 3, 5] print a[10:20] # 结果会报异常吗?
Wir vergossen Tränen, als wir die Ergebnisse sahen, anstatt einen IndexError zurückzugeben , wir haben direkt leer zurückgegeben. Dies hat uns zu dem Schluss gebracht, dass die Syntax tatsächlich ähnlich ist, die Dinge dahinter definitiv unterschiedlich sind, also versuchen wir, die Ergebnisse gemeinsam zu erklären
>>> a = [1, 2, 3, 5] >>> print a[10:20] []
>>> s = '23123123123' >>> print s[400:2000] '' >>> t = (1, 2, 3,4) >>> print t[200: 1000] ()
Bevor wir es aufdecken, müssen wir zunächst herausfinden, wie Python mit diesem Slice umgeht. Wir können das dis-Modul verwenden, um zu helfen:
Hier ist eine kurze Einführung in dis-Module. Erfahrene Veteranen wissen alle, dass es bei der Interpretation eines Skripts durch Python auch einen Kompilierungsprozess gibt. Das Ergebnis der Kompilierung ist die Pyc-Datei, die wir oft sehen und die aus Bytes besteht codeobject object code, und dis zeigt diese Bytecodes auf eindrucksvollere Weise an, sodass wir den Ausführungsprozess sehen können. Im Folgenden finden Sie eine Erklärung der Ausgabespalten von dis:
############# 切片 ################ [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
. Der Hauptunterschied besteht darin, dass test.py-Slices den Bytecode SLICE + verwenden 3 wird implementiert, und der einzelne Indexwert von test2.py wird hauptsächlich durch den Bytecode BINARY_SUBSCR implementiert. Wie wir vermutet haben, handelt es sich bei der ähnlichen Syntax um einen völlig anderen Code. Da es sich bei dem, was wir diskutieren möchten, um Slicing (SLICE+3) handelt, werden wir BINARY_SUBSCR nicht erweitern Interessierte Kinder können den entsprechenden Quellcode überprüfen, um mehr über die spezifische Implementierung zu erfahren. Speicherort: python/object/ceval.c
irgendwann ausführen werden, aber dies sq_slice ist etwas Besonderes, da verschiedene Objekte unterschiedliche entsprechende Funktionen haben. Im Folgenden sind die entsprechenden Funktionen aufgeführt:
Weil es drei sind Die Funktionsimplementierungen sind ungefähr gleich Daher müssen wir nur eine davon analysieren. Das Folgende ist eine Analyse der Slicing-Funktion der Liste:
/*取自: 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)
Fazit
// 字符串对象 StringObject.c: (ssizessizeargfunc)string_slice, /*sq_slice*/ // 列表对象 ListObject.c: (ssizessizeargfunc)list_slice, /* sq_slice */ // 元组 TupleObject.c: (ssizessizeargfunc)tupleslice, /* sq_slice */
Wie aus der Slicing-Funktion ersichtlich ist, die der Funktion sq_slice oben entspricht, werden die linken und rechten Indizes bei Verwendung von Slicing der Länge der Sequenz neu zugewiesen, wenn sie größer als die Länge der Sequenz sind anfängliches Schneiden: print a[10:20]
, was tatsächlich ausgeführt wird: print a4:4
Durch diese Analyse werden Sie nicht mehr verwirrt sein, wenn Sie auf ein Segment stoßen, dessen Index größer als die Länge des Objekts ist~
Das obige ist der detaillierte Inhalt vonDetailliertes Beispiel für das Indexproblem des Sequence Slicing in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!