Frage Die Python-Slice-Notation verstehen


Ich brauche eine gute Erklärung (Referenzen sind ein Plus) auf Pythons Slice-Notation.

Diese Notation braucht für mich etwas Aufhebens.

Es sieht extrem kraftvoll aus, aber ich habe mich nicht richtig verstanden.


2290
2018-02-03 22:31


Ursprung


Antworten:


Es ist wirklich ziemlich einfach:

a[start:end] # items start through end-1
a[start:]    # items start through the rest of the array
a[:end]      # items from the beginning through end-1
a[:]         # a copy of the whole array

Es gibt auch die step Wert, der mit jedem der oben genannten verwendet werden kann:

a[start:end:step] # start through not past end, by step

Der wichtigste Punkt zu erinnern ist, dass die :end Wert repräsentiert den ersten Wert nicht in der ausgewählten Scheibe. Also, der Unterschied zwischen end und start ist die Anzahl der ausgewählten Elemente (wenn step ist 1, der Standardwert).

Das andere Feature ist das start oder end vielleicht ein Negativ Nummer, was bedeutet, dass es vom Ende des Arrays statt vom Anfang zählt. Damit:

a[-1]    # last item in the array
a[-2:]   # last two items in the array
a[:-2]   # everything except the last two items

Ähnlich, step kann eine negative Zahl sein:

a[::-1]    # all items in the array, reversed
a[1::-1]   # the first two items, reversed
a[:-3:-1]  # the last two items, reversed
a[-3::-1]  # everything except the last two items, reversed

Python ist freundlich zum Programmierer, wenn es weniger Elemente gibt als Sie verlangen. Zum Beispiel, wenn Sie danach fragen a[:-2] und a Enthält nur ein Element, Sie erhalten eine leere Liste anstelle eines Fehlers. Manchmal würden Sie den Fehler bevorzugen, also müssen Sie sich bewusst sein, dass dies passieren kann.


3094
2018-02-03 22:48



Das Python-Tutorial redet darüber (scrolle ein wenig runter bis du zu dem Teil über Slicing kommst).

Das ASCII-Art-Diagramm ist auch hilfreich, um sich daran zu erinnern, wie Slices funktionieren:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

Eine Möglichkeit, sich daran zu erinnern, wie Slices funktionieren, besteht darin, sich die Indizes als Zeiger vorzustellen zwischen Zeichen, wobei die linke Kante des ersten Zeichens mit 0 nummeriert ist. Dann die rechte Kante des letzten Zeichens einer Zeichenkette von n Zeichen hat Index n.


394
2018-02-03 22:49



Aufzählung der Möglichkeiten, die die Grammatik erlaubt:

>>> seq[:]                # [seq[0],   seq[1],          ..., seq[-1]    ]
>>> seq[low:]             # [seq[low], seq[low+1],      ..., seq[-1]    ]
>>> seq[:high]            # [seq[0],   seq[1],          ..., seq[high-1]]
>>> seq[low:high]         # [seq[low], seq[low+1],      ..., seq[high-1]]
>>> seq[::stride]         # [seq[0],   seq[stride],     ..., seq[-1]    ]
>>> seq[low::stride]      # [seq[low], seq[low+stride], ..., seq[-1]    ]
>>> seq[:high:stride]     # [seq[0],   seq[stride],     ..., seq[high-1]]
>>> seq[low:high:stride]  # [seq[low], seq[low+stride], ..., seq[high-1]]

Natürlich, wenn (high-low)%stride != 0, dann ist der Endpunkt etwas niedriger als high-1.

Ob stride ist negativ, die Reihenfolge ist ein bisschen verändert, seit wir zählen:

>>> seq[::-stride]        # [seq[-1],   seq[-1-stride],   ..., seq[0]    ]
>>> seq[high::-stride]    # [seq[high], seq[high-stride], ..., seq[0]    ]
>>> seq[:low:-stride]     # [seq[-1],   seq[-1-stride],   ..., seq[low+1]]
>>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]

Erweitertes Slicing (mit Kommas und Ellipsen) wird meist nur von speziellen Datenstrukturen (wie Numpy) verwendet; die grundlegenden Sequenzen unterstützen sie nicht.

>>> class slicee:
...     def __getitem__(self, item):
...         return `item`
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'

310
2018-02-03 23:08



Die obigen Antworten behandeln keine Slice-Zuweisung:

>>> r=[1,2,3,4]
>>> r[1:1]
[]
>>> r[1:1]=[9,8]
>>> r
[1, 9, 8, 2, 3, 4]
>>> r[1:1]=['blah']
>>> r
[1, 'blah', 9, 8, 2, 3, 4]

Dies kann auch den Unterschied zwischen Slicing und Indizierung verdeutlichen.


199
2018-01-18 21:37



Erläutern Sie die Slice-Notation von Python

Kurz gesagt, die Doppelpunkte (:) in tiefgestellter Notation (subscriptable[subscriptarg]) mach Slice-Notation - welche die optionalen Argumente hat, start, stop, step:

sliceable[start:stop:step]

Python-Slicing ist eine rechentechnisch schnelle Methode, um systematisch auf Teile Ihrer Daten zuzugreifen. Meiner Meinung nach, um selbst ein fortgeschrittener Python-Programmierer zu sein, ist es ein Aspekt der Sprache, mit dem man vertraut sein muss.

Wichtige Definitionen

Lassen Sie uns zunächst einige Begriffe definieren:

Anfang: der Anfangsindex des Slice, es wird das Element in diesem Index enthalten, es sei denn es ist das gleiche wie halt, ist standardmäßig 0, d. h. der erste Index. Wenn es negativ ist, bedeutet es zu starten n Gegenstände vom Ende.

halt: der End-Index der Scheibe, tut es nicht Fügen Sie das Element in diesem Index ein, standardmäßig die Länge der Sequenz, die in Scheiben geschnitten wird, dh bis einschließlich des Endes.

Schritt: Der Wert, um den der Index erhöht wird, wird standardmäßig auf 1 gesetzt. Wenn der Wert negativ ist, wird das iterable in umgekehrter Reihenfolge angezeigt.

Wie funktioniert die Indexierung?

Sie können eine dieser positiven oder negativen Zahlen eingeben. Die Bedeutung der positiven Zahlen ist einfach, aber für negative Zahlen, genau wie die Indizes in Python, zählt man rückwärts vom Ende für die Anfang und haltund für die Schritt, dekrementieren Sie einfach Ihren Index. Dieses Beispiel ist aus dem Tutorial der Dokumentation, aber ich habe es leicht modifiziert, um anzuzeigen, auf welches Element in einer Sequenz jeder Index verweist:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
   0   1   2   3   4   5 
  -6  -5  -4  -3  -2  -1

Wie das Schneiden funktioniert

Um die Slice-Notation mit einer Sequenz zu verwenden, die sie unterstützt, müssen Sie mindestens einen Doppelpunkt in die eckigen Klammern einschließen, die der Sequenz folgen (was eigentlich implementieren Sie die __getitem__ Methode der Sequenz, nach dem Python-Datenmodell.)

Die Slice-Notation funktioniert folgendermaßen:

sequence[start:stop:step]

Und erinnern Sie sich, dass es Standardwerte für gibt Anfang, halt, und Schritt, um auf die Standardwerte zuzugreifen, lassen Sie das Argument einfach weg.

Die Slice-Notation, um die letzten neun Elemente einer Liste (oder einer anderen Sequenz, die sie unterstützt, wie eine Zeichenfolge) zu erhalten, würde folgendermaßen aussehen:

my_list[-9:]

Wenn ich das sehe, lese ich den Teil in den Klammern als "9. vom Ende bis zum Ende". (Eigentlich kürze ich es mental als "-9, auf")

Erläuterung:

Die vollständige Notation ist

my_list[-9:None:None]

und die Standardwerte zu ersetzen (eigentlich wenn step ist negativ, stopder Standard ist -len(my_list) - 1, damit None für Stop bedeutet eigentlich nur, dass es zu dem jeweiligen Endschritt führt, zu dem es geht):

my_list[-9:len(my_list):1]

Das Doppelpunkt, :, sagt Python, dass Sie ihm ein Stück und keinen regulären Index geben. Deshalb ist die idiomatische Methode, eine flache Kopie von Listen in Python 2 zu erstellen

list_copy = sequence[:]

Und Clearing sie ist mit:

del my_list[:]

(Python 3 bekommt eine list.copy und list.clear Methode.)

Wann step ist negativ, die Voreinstellungen für start und stop Veränderung

Standardmäßig, wenn der step Argument ist leer (oder None), ist es zugeordnet +1.

Sie können jedoch eine negative ganze Zahl übergeben, und die Liste (oder die meisten anderen standardmäßigen Slicables) wird vom Ende zum Anfang geschnitten.

Ein negativer Slice ändert daher die Standardwerte für start und stop!

Bestätige dies in der Quelle

Ich möchte die Benutzer ermutigen, sowohl die Quelle als auch die Dokumentation zu lesen. Das Quellcode für Slice-Objekte und diese Logik finden Sie hier. Zuerst bestimmen wir, ob step ist negativ:

 step_is_negative = step_sign < 0;

Wenn ja, ist die untere Grenze -1  Das bedeutet, dass wir den ganzen Weg bis einschließlich des Anfangs schneiden, und die obere Grenze ist die Länge minus 1, was bedeutet, dass wir am Ende beginnen. (Beachten Sie, dass die Semantik davon -1 ist anders von einem -1 dass Benutzer in Python Indizes übergeben können, die den letzten Eintrag anzeigen.)

if (step_is_negative) {
    lower = PyLong_FromLong(-1L);
    if (lower == NULL)
        goto error;

    upper = PyNumber_Add(length, lower);
    if (upper == NULL)
        goto error;
}

Andernfalls step ist positiv, und die untere Grenze ist Null und die obere Grenze (die wir bis zu, aber nicht einschließen) ist die Länge der geschnittenen Liste.

else {
    lower = _PyLong_Zero;
    Py_INCREF(lower);
    upper = length;
    Py_INCREF(upper);
}

Dann müssen wir möglicherweise die Standardwerte für anwenden start und stop - der Standard dann für start wird als obere Grenze berechnet, wenn step ist negativ:

if (self->start == Py_None) {
    start = step_is_negative ? upper : lower;
    Py_INCREF(start);
}

und stop, die untere Grenze:

if (self->stop == Py_None) {
    stop = step_is_negative ? lower : upper;
    Py_INCREF(stop);
}

Gib deinen Scheiben einen beschreibenden Namen!

Sie können es nützlich finden, die Scheibe von der Übergabe an die zu trennen list.__getitem__ Methode (Das tun die eckigen Klammern). Selbst wenn Sie es nicht neu sind, hält es Ihren Code lesbarer, sodass andere, die Ihren Code lesen müssen, leichter verstehen können, was Sie tun.

Sie können jedoch nicht einfach ganze Zahlen, die durch Doppelpunkte getrennt sind, einer Variablen zuweisen. Sie müssen das Slice-Objekt verwenden:

last_nine_slice = slice(-9, None)

Das zweite Argument, None, ist erforderlich, damit das erste Argument als interpretiert wird start Streit sonst wäre es das stop Streit.

Sie können das Slice-Objekt dann an Ihre Sequenz übergeben:

>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]

Es ist interessant, dass Bereiche auch Scheiben nehmen:

>>> range(100)[last_nine_slice]
range(91, 100)

Überlegungen zum Speicher:

Da Slices von Python-Listen neue Objekte im Speicher erstellen, ist eine weitere wichtige Funktion, auf die Sie achten sollten itertools.islice. Normalerweise möchten Sie über ein Segment iterieren und es nicht nur statisch im Speicher erstellen. islice ist perfekt dafür. Ein Vorbehalt, es unterstützt keine negativen Argumente start, stop, oder stepWenn dies ein Problem ist, müssen Sie möglicherweise Indizes berechnen oder das iterable im Voraus umkehren.

length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)

und nun:

>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]

Die Tatsache, dass Listenschnitte eine Kopie erstellen, ist eine Eigenschaft von Listen selbst. Wenn Sie erweiterte Objekte wie einen Pandas DataFrame schneiden, wird möglicherweise eine Ansicht des Originals und keine Kopie zurückgegeben.


184
2017-07-12 13:19



Und ein paar Dinge, die mir nicht sofort klar waren, als ich die Slicing-Syntax zum ersten Mal sah:

>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]

Einfache Möglichkeit, Sequenzen umzukehren!

Und wenn Sie aus irgendeinem Grund jeden zweiten Gegenstand in der umgekehrten Reihenfolge wollten:

>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]

124
2018-02-03 23:15



Fand diesen tollen Tisch bei http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

Python indexes and slices for a six-element list.
Indexes enumerate the elements, slices enumerate the spaces between the elements.

Index from rear:    -6  -5  -4  -3  -2  -1      a=[0,1,2,3,4,5]    a[1:]==[1,2,3,4,5]
Index from front:    0   1   2   3   4   5      len(a)==6          a[:5]==[0,1,2,3,4]
                   +---+---+---+---+---+---+    a[0]==0            a[:-2]==[0,1,2,3]
                   | a | b | c | d | e | f |    a[5]==5            a[1:2]==[1]
                   +---+---+---+---+---+---+    a[-1]==5           a[1:-1]==[1,2,3,4]
Slice from front:  :   1   2   3   4   5   :    a[-2]==4
Slice from rear:   :  -5  -4  -3  -2  -1   :
                                                b=a[:]
                                                b==[0,1,2,3,4,5] (shallow copy of a)

84
2017-09-06 06:50



In Python 2.7

Schneiden in Python

[a:b:c]

len = length of string, tuple or list

c -- default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.

a --  When c is positive or blank, default is 0. When c is negative, default is -1.

b --  When c is positive or blank, default is len. When c is negative, default is -(len+1).

Die Indexzuordnung ist sehr wichtig.

In forward direction, starts at 0 and ends at len-1

In backward direction, starts at -1 and ends at -len

Wenn Sie [a: b: c] sagen, sagen Sie, abhängig von dem Vorzeichen von c (vorwärts oder rückwärts), beginnen Sie bei a und enden Sie bei b (ohne Element bei bth-Index). Verwenden Sie die obige Indexierungsregel und denken Sie daran, dass Sie nur Elemente in diesem Bereich finden werden:

-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1

Aber dieser Bereich geht in beiden Richtungen unendlich weiter:

...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....

Beispielsweise:

             0    1    2   3    4   5   6   7   8   9   10   11
             a    s    t   r    i   n   g
    -9  -8  -7   -6   -5  -4   -3  -2  -1

Wenn Ihre Wahl von a, b und c eine Überlappung mit dem obigen Bereich zulässt, wenn Sie die Regeln für a, b, c oben durchlaufen, erhalten Sie entweder eine Liste mit Elementen (während der Überquerung berührt) oder Sie erhalten eine leere Liste.

Eine letzte Sache: Wenn a und b gleich sind, dann erhalten Sie auch eine leere Liste:

>>> l1
[2, 3, 4]

>>> l1[:]
[2, 3, 4]

>>> l1[::-1] # a default is -1 , b default is -(len+1)
[4, 3, 2]

>>> l1[:-4:-1] # a default is -1
[4, 3, 2]

>>> l1[:-3:-1] # a default is -1
[4, 3]

>>> l1[::] # c default is +1, so a default is 0, b default is len
[2, 3, 4]

>>> l1[::-1] # c is -1 , so a default is -1 and b default is -(len+1)
[4, 3, 2]


>>> l1[-100:-200:-1] # Interesting
[]

>>> l1[-1:-200:-1] # Interesting
[4, 3, 2]


>>> l1[-1:-1:1]
[]


>>> l1[-1:5:1] # Interesting
[4]


>>> l1[1:-7:1]
[]

>>> l1[1:-7:-1] # Interesting
[3, 2]

>>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
[4]

84
2017-10-22 05:33



Nachdem ich es ein wenig benutzt habe, stelle ich fest, dass die einfachste Beschreibung darin besteht, dass es genauso ist wie die Argumente in einer for-Schleife ...

(from:to:step)

einige von ihnen sind optional

(:to:step)
(from::step)
(from:to)

Dann braucht die negative Indizierung nur die Länge der Zeichenkette zu den negativen Indizes hinzuzufügen, um sie zu verstehen.

Das funktioniert bei mir trotzdem ...


47
2018-02-19 20:52