Heim > Backend-Entwicklung > Python-Tutorial > Detailliertes Beispiel für das Indexproblem des Sequence Slicing in Python

Detailliertes Beispiel für das Indexproblem des Sequence Slicing in Python

黄舟
Freigeben: 2017-06-18 11:29:32
Original
1095 Leute haben es durchsucht

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 [:]   # 复制整个列表
Nach dem Login kopieren

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
Nach dem Login kopieren

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
Nach dem Login kopieren

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:

Das Ergebnis ist tatsächlich: [], was sich etwas interessant anfühlt. Nur Listen können das, was ist mit Strings, was ist mit Tupeln?


# version: python2.7

a = [1, 2, 3, 5]
print a[10:20] # 结果会报异常吗?
Nach dem Login kopieren

Die Ergebnisse ähneln denen der Liste und geben ihre eigenen leeren Ergebnisse zurück.


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]
[]
Nach dem Login kopieren

Prinzipielle Analyse


>>> s = &#39;23123123123&#39;
>>> print s[400:2000]
&#39;&#39;
>>> t = (1, 2, 3,4)
>>> print t[200: 1000]
()
Nach dem Login kopieren

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:

Die erste Spalte ist Die Zahlen sind die Zeilennummern des ursprünglichen Quellcodes.


############# 切片 ################
[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
Nach dem Login kopieren
Die zweite Spalte ist der Offset des Bytecodes: LOAD_CONST befindet sich in Zeile 0. Und so weiter.

Die dritte Spalte ist der für Menschen lesbare Name des Bytecodes. Sie sind für Programmierer vorbereitet
  • Die vierte Spalte stellt die Parameter der Anweisung dar
  • Die fünfte Spalte enthält die berechneten tatsächlichen Parameter
  • Ich werde oben nicht auf Details eingehen, es ist der Prozess des Lesens von Konstanten und des Speicherns von
  • Variablen

    . 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

  • Dann besprechen wir SLICE+3

Obwohl der obige Code etwas lang ist, wurden die wichtigsten Stellen auskommentiert, und wir müssen nur auf diese Stellen achten. Wie oben wissen wir, dass wir

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("&#39;%.200s&#39; object is unsliceable", s);
Nach dem Login kopieren

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 */
Nach dem Login kopieren

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!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage