Wie funktioniert die Zuweisung mit Python List Slice?

99

Python-Dokument sagt, dass das Schneiden einer Liste eine neue Liste zurückgibt.
Wenn nun eine "neue" Liste zurückgegeben wird, habe ich die folgenden Zweifel in Bezug auf "Zuordnung zu Slices".

a = [1, 2, 3]
a[0:2] = [4, 5]
print a

Jetzt wäre die Ausgabe:

[4, 5, 3] 
  1. Wie kann etwas, das etwas zurückgibt, auf die linke Seite des Ausdrucks kommen?
  2. Ja, ich habe die Dokumente gelesen und es heißt, dass dies möglich ist. Da das Schneiden einer Liste eine "neue" Liste zurückgibt, warum wird die ursprüngliche Liste geändert? Ich kann die Mechanik dahinter nicht verstehen.
Kartik Anand
quelle
@ Mark Longair Entschuldigung, ich dachte, nur Code soll formatiert werden, nicht die Ausgabe
Kartik Anand
2
Siehe: 6.2 Zuweisungserklärungen
Josh Lee
7
Verstehst du was a[0] = 4tun würde?
Josh Lee
1
@KartikAnand Die Slice-Zuweisung ist ein spezielles Szenario, in dem keine neue Liste erstellt wird. Es ist nicht sinnvoll, ein Objekt ohne Namensbindung auf der linken Seite von zu erstellen. =Anstatt dies als ungültige Syntax zu verwerfen, verwandelt Python es in etwas, das eher dem entspricht, was Sie vielleicht erwarten. Da Python keine Referenzen hat, würde es nicht funktionieren, wenn das Ergebnis eines Slice die ursprüngliche Liste ändert. Du bekommst eine Kopie. Wenn Sie weitere Informationen zu Ihrer Anwendung angegeben haben, können wir Ihnen möglicherweise besser dabei helfen, die Dinge auf "pythonische" Weise zu erledigen. :)
Casey Kuball
1
@Darthfett Ich arbeite gerade an keiner Anwendung, sondern unterrichte mich selbst in Python, bevor ich anfange, mir die Hände schmutzig zu machen :)
Kartik Anand

Antworten:

114

Sie verwechseln zwei unterschiedliche Operationen, die eine sehr ähnliche Syntax verwenden:

1) Schneiden:

b = a[0:2]

Dadurch wird eine Kopie des Slice erstellt aund zugewiesen b.

2) Slice-Zuordnung:

a[0:2] = b

Dies ersetzt das Slice von adurch den Inhalt von b.

Obwohl die Syntax ähnlich ist (ich stelle mir das vor!), Sind dies zwei verschiedene Operationen.

NPE
quelle
4
Das ist mein Zweifel, im zweiten Fall, warum ist das Stück einer neuen Liste nicht?
Kartik Anand
11
@ KartikAnand Weil es nicht ist. Das ist nicht das, was die Sprache angibt.
Marcin
Um klar zu sein, bedeutet "nimmt eine Scheibe von" wirklich "eine Kopie einer Scheibe von machen", woher ein Teil der Verwirrung kommt.
Mark Ransom
2
@ KartikAnand: Grundsätzlich ja. Der Dolmetscher weiß, welches welches ist, und behandelt sie angemessen.
NPE
1
@ Dublow: Sie können dies mit dem Modul itertools tun . Verwenden Sie für Ihren Fall die Funktion islice , with start=1, stop=None. Dadurch werden Kopien vermieden und eine verzögerte Auswertung verwendet (in Ihrem Fall ein verzögerter Zugriff auf die ursprüngliche Liste).
Spiros
66

Wenn Sie aauf der linken Seite des =Operators angeben , verwenden Sie die normale Zuweisung von Python , mit der der Name aim aktuellen Kontext so geändert wird, dass er auf den neuen Wert verweist. Dies ändert nichts an dem vorherigen Wert, auf den gezeigt awurde.

Indem Sie a[0:2]auf der linken Seite des =Operators angeben, teilen Sie Python mit, dass Sie die Slice-Zuweisung verwenden möchten . Die Slice-Zuweisung ist eine spezielle Syntax für Listen, mit der Sie Inhalte aus einer Liste einfügen, löschen oder ersetzen können:

Einfügen :

>>> a = [1, 2, 3]
>>> a[0:0] = [-3, -2, -1, 0]
>>> a
[-3, -2, -1, 0, 1, 2, 3]

Löschung :

>>> a
[-3, -2, -1, 0, 1, 2, 3]
>>> a[2:4] = []
>>> a
[-3, -2, 1, 2, 3]

Ersatz :

>>> a
[-3, -2, 1, 2, 3]
>>> a[:] = [1, 2, 3]
>>> a
[1, 2, 3]

Hinweis:

Die Länge des Slice kann sich von der Länge der zugewiesenen Sequenz unterscheiden, wodurch sich die Länge der Zielsequenz ändert, wenn die Zielsequenz dies zulässt. - Quelle

Die Slice-Zuweisung bietet eine ähnliche Funktion wie das Auspacken von Tupeln . Zum Beispiel a[0:1] = [4, 5]ist äquivalent zu:

# Tuple Unpacking
a[0], a[1] = [4, 5]

Mit Tuple Unpacking können Sie nicht sequentielle Listen ändern:

>>> a
[4, 5, 3]
>>> a[-1], a[0] = [7, 3]
>>> a
[3, 5, 7]

Das Auspacken von Tupeln ist jedoch auf das Ersetzen beschränkt, da Sie keine Elemente einfügen oder entfernen können.

Vor und nach all diesen Operationen aist die gleiche genaue Liste. Python bietet einfach einen guten syntaktischen Zucker, um eine Liste an Ort und Stelle zu ändern.

Casey Kuball
quelle
6
Ähnlich, aber nicht identisch, da links und rechts ungleich viele Elemente vorhanden sein können.
Mark Ransom
@ MarkRansom Das ist ein ausgezeichneter Punkt, ich habe weitere Informationen hinzugefügt, um dies deutlich zu machen.
Casey Kuball
2
Ist a[:] = some_listgleichwertig a = some_list[:]oder a = some_list?
Jadkik94
2
@ jadkik94 Weder noch. a[:] = some_listsetzt jedes Element von aauf das von some_list. Wenn Sie eine der von Ihnen erwähnten Aktionen ausführen, ändert sich das, was aist. Zum Beispiel : a = [1, 2, 3] b = a a[:] = [4, 5, 6] a is b. Die letzte Zeile wäre False, wenn der aWert geändert würde , anstatt ihn zu mutieren.
Casey Kuball
@Darthfett Interessant, ich hatte anders gefunden :) Danke.
Jadkik94
25

Ich bin auf dieselbe Frage gestoßen, die sich auf die Sprachspezifikation bezieht. Nach Zuweisung-Aussagen ,

  1. Wenn die linke Seite der Zuweisung ein Abonnement ist, ruft Python __setitem__dieses Objekt auf. a[i] = xist äquivalent zu a.__setitem__(i, x).

  2. Wenn die linke Seite der Zuweisung Slice ist, ruft Python ebenfalls auf __setitem__, jedoch mit unterschiedlichen Argumenten: a[1:4]=[1,2,3]entspricht a.__setitem__(slice(1,4,None), [1,2,3])

Aus diesem Grund verhält sich das Listen-Slice auf der linken Seite von '=' anders.

Stan
quelle
4

Durch Schneiden auf der linken Seite eines Zuweisungsvorgangs geben Sie an, welchen Elementen zugewiesen werden soll.

fraxel
quelle