Wenn wir nehmen b = [1,2,3]
und wenn wir versuchen:b+=(4,)
Es kehrt zurück b = [1,2,3,4]
, aber wenn wir es versuchen, b = b + (4,)
funktioniert es nicht.
b = [1,2,3]
b+=(4,) # Prints out b = [1,2,3,4]
b = b + (4,) # Gives an error saying you can't add tuples and lists
Ich habe erwartet b+=(4,)
, dass dies fehlschlägt, da Sie keine Liste und kein Tupel hinzufügen können, aber es hat funktioniert. Also habe ich versucht b = b + (4,)
, das gleiche Ergebnis zu erwarten, aber es hat nicht funktioniert.
python
python-3.x
list
tuples
Supun Dasantha Kuruppu
quelle
quelle
Antworten:
Das Problem mit "Warum" -Fragen ist, dass sie normalerweise mehrere verschiedene Dinge bedeuten können. Ich werde versuchen, jeden zu beantworten, von dem ich glaube, dass Sie ihn im Sinn haben.
"Warum kann es anders funktionieren?" was zB von diesem beantwortet wird . Grundsätzlich wird
+=
versucht, verschiedene Methoden des Objekts zu verwenden:__iadd__
(die nur auf der linken Seite aktiviert sind), vs__add__
und__radd__
("Reverse Add", auf der rechten Seite aktiviert, wenn die linke Seite keine hat__add__
) für+
."Was genau macht jede Version?" Kurz gesagt, die
list.__iadd__
Methode macht dasselbe wielist.extend
(aber aufgrund des Sprachdesigns gibt es immer noch eine Zuordnung zurück).Dies bedeutet zum Beispiel auch, dass
+
Erstellt natürlich ein neues Objekt, erfordert jedoch explizit eine andere Liste, anstatt zu versuchen, Elemente aus einer anderen Sequenz herauszuziehen."Warum ist es für + = nützlich, dies zu tun? Es ist effizienter; die
extend
Methode muss kein neues Objekt erstellen. Natürlich hat dies manchmal einige überraschende Auswirkungen (wie oben), und im Allgemeinen geht es bei Python nicht wirklich um Effizienz , aber diese Entscheidungen wurden vor langer Zeit getroffen."Was ist der Grund, das Hinzufügen von Listen und Tupeln mit + nicht zuzulassen?" Siehe hier (danke, @ splash58); Eine Idee ist, dass (Tupel + Liste) den gleichen Typ wie (Liste + Tupel) erzeugen sollte, und es ist nicht klar, welcher Typ das Ergebnis sein sollte.
+=
hat dieses problem nicht, daa += b
sollte natürlich den typ von nicht änderna
.quelle
|
, so dass mein Beispiel irgendwie ruiniert wird. Wenn ich später an ein klareres Beispiel denke, tausche ich es aus.|
für Mengen ist ein Pendleroperator,+
für Listen jedoch nicht. Aus diesem Grund denke ich nicht, dass das Argument über Typmehrdeutigkeit besonders stark ist. Da der Bediener nicht pendelt, warum sollte er dasselbe für Typen verlangen? Man könnte einfach zustimmen, dass das Ergebnis den Typ des lhs hat. Auf der anderen Seite wirdlist + iterator
der Entwickler durch Einschränkung aufgefordert, seine Absichten genauer zu formulieren. Wenn Sie eine neue Liste erstellen möchten, die das Material enthält, dasa
um das Material erweitert wurde,b
gibt es bereits eine Möglichkeit, dies zu tun :new = a.copy(); new += b
. Es ist noch eine Linie, aber kristallklar.a += b
sich anders verhält alsa = a + b
nicht Effizienz ist. Es ist tatsächlich so, dass Guido das gewählte Verhalten als weniger verwirrend ansah. Stellen Sie sich eine Funktion vor, die eine Listea
als Argument empfängt und dann ausführta += [1, 2, 3]
. Diese Syntax sieht sicherlich so aus, als würde sie die vorhandene Liste ändern, anstatt eine neue Liste zu erstellen. Daher wurde die Entscheidung getroffen, dass sie sich entsprechend der Intuition der meisten Menschen über das erwartete Ergebnis verhalten soll. Der Mechanismus musste jedoch auch für unveränderliche Typen wieint
s funktionieren , was zum aktuellen Design führte.a += b
eine Abkürzung füra = a + b
, wie Ruby - tat, aber ich kann verstehen , wie wir dort ankamen.Sie sind nicht gleichwertig:
ist eine Abkürzung für:
während
+
Listen verkettet, also durch:Sie versuchen, ein Tupel mit einer Liste zu verknüpfen
quelle
Wenn Sie dies tun:
wird dazu konvertiert:
Unter der Haube ruft es auf
b.extend((4,))
,extend
akzeptiert einen Iterator und deshalb funktioniert das auch:aber wenn Sie dies tun:
wird dazu konvertiert:
Nur Listenobjekt akzeptieren.
quelle
Aus den offiziellen Dokumenten für veränderbare Sequenztypen :
sind definiert als:
Was anders ist als definiert als:
Dies bedeutet auch, dass jeder Sequenztyp funktioniert
t
, einschließlich eines Tupels wie in Ihrem Beispiel.Es funktioniert aber auch für Reichweiten und Generatoren! Zum Beispiel können Sie auch Folgendes tun:
quelle
Die "erweiterten" Zuweisungsoperatoren wie
+=
wurden in Python 2.0 eingeführt, das im Oktober 2000 veröffentlicht wurde. Das Design und die Begründung sind in PEP 203 beschrieben . Eines der erklärten Ziele dieser Betreiber war die Unterstützung des Vor-Ort-Betriebs. Schreibensoll die Liste
a
an Ort und Stelle aktualisieren . Dies ist wichtig, wenn andere Verweise auf die Liste vorhanden sinda
, z. B. wanna
als Funktionsargument empfangen wurde.Die Operation kann jedoch nicht immer an Ort und Stelle ausgeführt werden, da viele Python-Typen, einschließlich Ganzzahlen und Zeichenfolgen, unveränderlich sind , sodass z. B.
i += 1
eine Ganzzahli
möglicherweise nicht an Ort und Stelle ausgeführt werden kann.Zusammenfassend sollte gesagt werden, dass erweiterte Zuweisungsoperatoren nach Möglichkeit an Ort und Stelle arbeiten und ansonsten ein neues Objekt erstellen sollten. Um diese Entwurfsziele zu vereinfachen, wurde der Ausdruck
x += y
so angegeben, dass er sich wie folgt verhält:x.__iadd__
definiert,x.__iadd__(y)
wird ausgewertet.x.__add__
implementiert,x.__add__(y)
ausgewertet.y.__radd__
implementiert,y.__radd__(x)
ausgewertet.Das erste Ergebnis, das durch diesen Prozess erhalten wird, wird zurück zugewiesen
x
(es sei denn, dieses Ergebnis ist derNotImplemented
Singleton. In diesem Fall wird die Suche mit dem nächsten Schritt fortgesetzt).Dieser Prozess ermöglicht die Implementierung von Typen, die direkte Änderungen unterstützen
__iadd__()
. Typen, die keine direkte Änderung unterstützen, müssen keine neuen magischen Methoden hinzufügen, da Python automatisch auf im Wesentlichen zurückgreiftx = x + y
.Kommen wir nun zu Ihrer eigentlichen Frage: Warum können Sie einer Liste mit einem erweiterten Zuweisungsoperator ein Tupel hinzufügen? Aus dem Speicher war der Verlauf ungefähr so: Die
list.__iadd__()
Methode wurde implementiert, um einfach die bereits vorhandenelist.extend()
Methode in Python 2.0 aufzurufen . Bei der Einführung von Iteratoren in Python 2.1 wurde dielist.extend()
Methode aktualisiert, um beliebige Iteratoren zu akzeptieren. Das Endergebnis dieser Änderungen war, dassmy_list += my_tuple
ab Python 2.1 funktioniert wurde. Dielist.__add__()
Methode sollte jedoch niemals beliebige Iteratoren als rechtes Argument unterstützen - dies wurde für eine stark typisierte Sprache als unangemessen angesehen.Ich persönlich denke, dass die Implementierung erweiterter Operatoren in Python etwas zu komplex war. Es hat viele überraschende Nebenwirkungen, zB dieser Code:
Die zweite Zeile erhöht
TypeError: 'tuple' object does not support item assignment
, aber die Operation erfolgreich ohnehin durchgeführt -t
wird([42, 44], [43])
nach der Zeile ausgeführt werden, die den Fehler auslöst.quelle
Die meisten Leute würden erwarten, dass X + = Y gleich X = X + Y ist. In der Python Pocket Reference (4. Ausgabe) von Mark Lutz heißt es auf Seite 57: "Die folgenden zwei Formate sind ungefähr gleichwertig: X = X + Y, X + = Y ". Die Personen, die Python angegeben haben, haben sie jedoch nicht gleichwertig gemacht. Möglicherweise war dies ein Fehler, der dazu führen wird, dass frustrierte Programmierer stundenlang debuggen, solange Python verwendet wird, aber jetzt ist Python genau so. Wenn X ein veränderlicher Sequenztyp ist, entspricht X + = Y X.extend (Y) und nicht X = X + Y.
quelle
Da es erklärt hier , wenn
array
nicht implementiert__iadd__
Verfahren, dasb+=(4,)
wäre nur ein Shorthanded von ,b = b + (4,)
aber es ist offensichtlich nicht, soarray
tut implementieren__iadd__
Methode. Anscheinend ist die Implementierung der__iadd__
Methode ungefähr so:Wir wissen jedoch, dass der obige Code nicht die eigentliche Implementierung der
__iadd__
Methode ist, aber wir können annehmen und akzeptieren, dass es so etwas wie eineextend
Methode gibt, dietupple
Eingaben akzeptiert .quelle