Warum funktioniert das Schneiden von Teilzeichenfolgen mit einem Index außerhalb des Bereichs?

86

Warum führt dies nicht 'example'[999:9999]zu Fehlern? Da der 'example'[9]Fall ist, was ist die Motivation dahinter?

Aufgrund dieses Verhaltens kann ich davon ausgehen, dass dies 'example'[3]im Wesentlichen / intern nicht dasselbe ist wie 'example'[3:4], obwohl beide zu derselben 'm'Zeichenfolge führen.

ijverig
quelle
17
[999:9999]ist kein Index, es ist ein Slice und hat eine andere Semantik. Aus dem Python-Intro: "Entartete Slice-Indizes werden ordnungsgemäß behandelt: Ein zu großer Index wird durch die Zeichenfolgengröße ersetzt. Eine Obergrenze, die kleiner als die Untergrenze ist, gibt eine leere Zeichenfolge zurück."
Wooble
2
@Wooble das ist die eigentliche Antwort
jondavidjohn
2
@Wooble Und weißt du warum es so ist? Vielen Dank für Ihre Klarstellung.
Ijverig
Warum? Sie müssten Guido fragen, aber ich finde es elegant, davon ausgehen zu können, dass ein Slice immer dieselbe Art von Sequenz ist wie die ursprüngliche Sequenz.
Wooble
1
@Lapinot ja, ich habe Code geschrieben, der von diesem Verhalten abhängt. Leider kann ich mich nicht an den genauen Code erinnern, daher kann ich Ihnen nicht sagen warum. Hat wahrscheinlich mit Teilzeichenfolgen zu tun; Eine leere Zeichenfolge zu erhalten kann manchmal genau das sein, was Sie wollen.
Mark Ransom

Antworten:

67

Du hast Recht! 'example'[3:4]und 'example'[3]sind grundlegend anders, und das Schneiden außerhalb der Grenzen einer Sequenz (zumindest für integrierte Funktionen) verursacht keinen Fehler.

Es mag zunächst überraschend sein, aber es macht Sinn, wenn Sie darüber nachdenken. Durch die Indizierung wird ein einzelnes Element zurückgegeben, durch das Schneiden wird jedoch eine Teilsequenz von Elementen zurückgegeben. Wenn Sie also versuchen, einen nicht vorhandenen Wert zu indizieren, gibt es nichts zurückzugeben. Wenn Sie jedoch eine Sequenz außerhalb der Grenzen schneiden, können Sie dennoch eine leere Sequenz zurückgeben.

Was hier verwirrend ist, ist, dass sich Zeichenfolgen etwas anders verhalten als Listen. Schauen Sie, was passiert, wenn Sie dasselbe mit einer Liste machen:

>>> [0, 1, 2, 3, 4, 5][3]
3
>>> [0, 1, 2, 3, 4, 5][3:4]
[3]

Hier ist der Unterschied offensichtlich. Bei Zeichenfolgen scheinen die Ergebnisse identisch zu sein, da es in Python kein einzelnes Zeichen außerhalb einer Zeichenfolge gibt. Ein einzelnes Zeichen ist nur eine Zeichenfolge mit 1 Zeichen.

(Die genaue Semantik des Schneidens außerhalb des Bereichs einer Sequenz finden Sie in der Antwort von mgilson .)

senderle
quelle
1
Ein Index außerhalb des Bereichs hätte zurückgegeben werden können, Noneanstatt einen Fehler zu machen - das ist die übliche Python-Konvention, wenn Sie nichts zurückgeben müssen.
Mark Ransom
7
@ MarkRansom, das stimmt; aber die Rückkehr Nonein diesem Fall würde es schwieriger macht zwischen einem Out-of-bounds - Index und einen sagen NoneWert in einer Liste an . Aber selbst wenn es dafür eine Problemumgehung gab, bleibt mir klar, dass die Rückgabe einer leeren Sequenz das Richtige ist, wenn ein Slice außerhalb der Grenzen angegeben wird. Es ist analog zur Vereinigung zweier disjunkter Mengen.
senderle
Um ganz klar zu sein, ich habe nicht gesagt, dass Sie sich geirrt haben. Ich sehe Ihren Standpunkt zu NoneWerten in einer Liste.
Mark Ransom
1
@ MarkRansom, ich weiß - Entschuldigung, wenn ich defensiv klang. Wirklich, ich wollte nur eine Ausrede, um mich auf die Mengenlehre zu beziehen :).
senderle
4
Aw, außer ich sagte "Vereinigung" statt "Kreuzung".
senderle
30

Um eine Antwort hinzuzufügen, die auf einen robusten Abschnitt in der Dokumentation verweist :

Bei einem Slice-Ausdruck wie s[i:j:k]:

Die Schicht von s von i nach j mit Schritt k ist definiert als die Folge von Elementen mit Index, x = i + n*kso dass 0 <= n < (j-i)/k. Mit anderen Worten sind die Indizes i, i+k, i+2*k, i+3*kund so weiter, zu stoppen , wenn j (aber nie einschließlich erreicht ist j ). Wenn k positiv ist, werden i und j auf reduziert, len(s)wenn sie größer sind

Wenn Sie schreiben s[999:9999], kehrt Python s[len(s):len(s)]seitdem zurück len(s) < 999und Ihr Schritt ist positiv ( 1- die Standardeinstellung).

mgilson
quelle
Vermutlich wann kist positiv iund jwerden auch erhöht, -len(s)wenn sie geringer sind? zBs = 'bac'; s[-100:2] == s[-len(s):2]
Chris_Rands
@Chris_Rands Wenn kpositiv, wird Python skaliert iund jso, dass sie den Grenzen der Sequenz entsprechen. In Ihrem Beispiel s[-100:2] == s[0:2]( == s[-len(s):2]übrigens). Ebenso s[-100:100] == s[0:2].
tylerc0816
Nett, danke. Dies ist eine bessere Antwort auf den obigen Kommentar von @ speedplane.
senderle
8

Das Schneiden wird von den integrierten Typen nicht auf Grenzen überprüft. Und obwohl beide Beispiele das gleiche Ergebnis zu haben scheinen, funktionieren sie unterschiedlich. Versuchen Sie es stattdessen mit einer Liste.

Ignacio Vazquez-Abrams
quelle