Ich habe keine Ahnung, wie diese eigentlich heißen, aber ich sehe sie die ganze Zeit. Die Python-Implementierung sieht ungefähr so aus:
x += 5
als Kurzschreibweise für x = x + 5
.
Aber warum wird dies als gute Praxis angesehen? Ich habe es in fast jedem Buch oder Programmier-Tutorial gelesen, das ich für Python, C, R usw. gelesen habe . Ich verstehe, dass es praktisch ist, drei Tastenanschläge einschließlich Leerzeichen zu sparen. Aber sie scheinen mich immer zu stören, wenn ich Code lese, und zumindest für mich ist es weniger lesbar, nicht mehr.
Fehlt mir ein klarer und offensichtlicher Grund, warum diese überall verwendet werden?
programming-practices
Fomite
quelle
quelle
x += 5
alsx = x + 5
? Oder ist es wirklich nur syntaktischer Zucker, wie Sie vorschlagen?Antworten:
Es ist keine Kurzschrift.
Das
+=
Symbol erschien in den 1970er Jahren in der C-Sprache und - mit der C-Idee "Smart Assembler" korrespondiert es mit einer deutlich anderen Maschinenanweisung und Adressierungsart:Dinge wie "
i=i+1
","i+=1
"und"++i
"entsprechen, obwohl sie auf abstrakter Ebene den gleichen Effekt haben, auf niedriger Ebene einer anderen Arbeitsweise des Prozessors.Insbesondere diese drei Ausdrücke, vorausgesetzt, die
i
Variable befindet sich in der Speicheradresse, die in einem CPU-Register gespeichert ist (nennen wir esD
- betrachten wir es als "Zeiger auf int"), und die ALU des Prozessors nimmt einen Parameter und gibt ein Ergebnis in einem zurück "Akku" (nennen wir es A - denken Sie daran als int).Mit diesen Einschränkungen (sehr häufig in allen Mikroprozessoren aus dieser Zeit) wird die Übersetzung höchstwahrscheinlich sein
Die erste Möglichkeit ist nicht optimal, sie ist jedoch allgemeiner, wenn Sie mit Variablen anstelle von Konstanten (
ADD A, B
oderADD A, (D+x)
) arbeiten oder komplexere Ausdrücke übersetzen (sie laufen alle im Push-Vorgang mit niedriger Priorität in einem Stapel zusammen, nennen Sie die hohe Priorität pop und wiederholen, bis alle Argumente beseitigt sind.Die zweite ist typischer für "Zustandsmaschine": Wir "evaluieren" nicht länger einen Ausdruck, sondern "operieren einen Wert": Wir verwenden weiterhin die ALU, vermeiden jedoch, dass Werte verschoben werden, damit das Ergebnis den Parameter ersetzen kann. Diese Art von Anweisung kann nicht verwendet werden, wenn kompliziertere Ausdrücke erforderlich sind:
i = 3*i + i-2
Kann nicht an Ort und Stelle ausgeführt werden, dai
mehrmals erforderlich.Die dritte - einfachere - betrachtet nicht einmal die Idee der "Addition", sondern verwendet eine "primitivere" (im rechnerischen Sinne) Schaltung für einen Zähler. Der Befehl ist kurzgeschlossen, wird schneller geladen und sofort ausgeführt, da das kombinatorische Netzwerk, das zum Nachrüsten eines Registers erforderlich ist, um es zu einem Zähler zu machen, kleiner und daher schneller als das eines Volladdierers ist.
Mit modernen Compilern (siehe C), die die Compileroptimierung ermöglichen, kann die Korrespondenz nach Belieben ausgetauscht werden, aber es gibt immer noch einen konzeptionellen Unterschied in der Semantik.
x += 5
meintAber
x = x + 5
heißt:Natürlich kann Optimierung
&x
stattdessen auf den Akku angewendet wirdAuf diese Weise wird der optimierte Code so gestaltet, dass er mit dem
x += 5
einen übereinstimmt .Dies ist jedoch nur möglich, wenn "x finden" keine Nebenwirkungen hat, ansonsten
und
sind semantisch unterschiedlich, da
x()
Nebenwirkungen (zugebenx()
ist eine Funktion, die seltsame Dinge tut und zurückgibtint*
) zweimal oder einmal auftreten.Die Äquivalenz zwischen
x = x + y
undx += y
ist daher auf den besonderen Fall zurückzuführen, in dem+=
und=
auf einen direkten l-Wert angewendet werden.Um auf Python umzusteigen, wurde die Syntax von C übernommen. Da es jedoch keine Übersetzung / Optimierung VOR der Ausführung in interpretierten Sprachen gibt, hängen die Dinge nicht unbedingt so eng zusammen (da es nur einen Analyseschritt weniger gibt). Ein Interpreter kann jedoch auf verschiedene Ausführungsroutinen für die drei Ausdruckstypen verweisen und dabei abhängig von der Art der Ausdrucksbildung und dem Auswertungskontext unterschiedlichen Maschinencode verwenden.
Für diejenigen, die mehr Details mögen ...
Jede CPU hat eine ALU (arithmetisch-logische Einheit), die im Grunde genommen ein kombinatorisches Netzwerk ist, dessen Ein- und Ausgänge in Abhängigkeit vom Operationscode des Befehls mit den Registern und / oder dem Speicher "verbunden" sind.
Binäroperationen werden typischerweise als "Modifikator eines Akkumulatorregisters" implementiert, wobei eine Eingabe "irgendwo" erfolgt, wobei sich irgendwo - innerhalb des Befehlsflusses selbst (typisch für Manifest Contant: ADD A 5) - innerhalb eines anderen Registers befinden kann (typisch für Ausdrucksberechnung mit temporaries (z. B. ADD AB) - innerhalb des Speichers an einer von einem Register vorgegebenen Adresse (typisch für das Abrufen von Daten, z. B. ADD A (H)) - H funktionieren in diesem Fall wie ein Dereferenzierungszeiger.
Mit diesem Pseudocode
x += 5
istwährend
x = x+5
istDas heißt, x + 5 gibt ein temporäres Objekt an, das später zugewiesen wird.
x += 5
arbeitet direkt auf x.Die tatsächliche Implementierung hängt vom tatsächlichen Befehlssatz des Prozessors ab: Wenn kein
ADD (.) c
Opcode vorhanden ist , wird der erste Code zum zweiten: no way.Wenn es einen solchen Opcode gibt und die Optimierung aktiviert ist, wird der zweite Ausdruck nach Eliminierung der Rückwärtsbewegung und Anpassung des Register-Opcodes der erste.
quelle
Je nachdem, wie Sie darüber nachdenken, ist es tatsächlich einfacher zu verstehen, weil es einfacher ist. Nehmen Sie zum Beispiel:
x = x + 5
ruft die mentale Verarbeitung von "nimm x, addiere fünf dazu und ordne dann diesen neuen Wert wieder x zu" aufx += 5
kann gedacht werden als "x um 5 erhöhen"Es ist also nicht nur eine Kurzform, sondern beschreibt die Funktionalität direkter. Beim Lesen von Codegegenständen ist es viel einfacher zu verstehen.
quelle
x = x + 5
mich immer noch beunruhigte. Als ich in einem späteren Alter in die Mathematik kam, störte mich das noch mehr. Verwendenx += 5
ist deutlich aussagekräftiger und als Ausdruck viel sinnvoller.reallyreallyreallylongvariablename = reallyreallyreallylongvariablename + 1
... oh nein !!! Ein TippfehlerZumindest in Python ,
x += y
undx = x + y
kann ganz andere Dinge tun.Zum Beispiel, wenn wir das tun
dann
a += [3]
ergibt sicha == b == [3]
, währenda = a + [3]
ergibt sicha == [3]
undb == []
. Das heißt,+=
Sie können das Objekt direkt ändern (möglicherweise können Sie die__iadd__
Methode so definieren, dass Sie so ziemlich alles tun, was Sie möchten), während Sie=
ein neues Objekt erstellen und die Variable daran binden.Dies ist sehr wichtig, wenn Sie mit NumPy numerisch arbeiten , da Sie häufig mehrere Verweise auf verschiedene Teile eines Arrays haben und Sie sicherstellen müssen, dass Sie nicht versehentlich Teile eines Arrays ändern, auf die es andere Verweise gibt. oder unnötigerweise Arrays kopieren (was sehr teuer sein kann).
quelle
__iadd__
: Es gibt Sprachen, in denen Sie einen unveränderlichen Verweis auf eine veränderbare Datenstruktur erstellen können, in deroperator +=
die definiert ist, z . B. scala:val sb = StringBuffer(); lb += "mutable structure"
vs.var s = ""; s += "mutable variable"
Dadurch wird der Inhalt der Datenstruktur weiter geändert, während die Variable auf eine neue verweist.Es heißt eine Redewendung . Programmiersprachen sind nützlich, da sie eine konsistente Methode zum Schreiben eines bestimmten Programmierkonstrukts darstellen.
Wann immer jemand schreibt
x += y
, wissen Sie, dass die Operationx
inkrementiert wirdy
und keine komplexere Operation (als Best Practice würde ich normalerweise keine komplizierteren Operationen und diese Syntaxkürzel mischen). Dies ist am sinnvollsten, wenn um 1 erhöht wird.quelle
++x
undx+=1
sind in C und Java (möglicherweise auch C #) äquivalent, jedoch nicht unbedingt in C ++, da dort eine komplexe Operatorsemantik vorliegt. Der Schlüssel ist, dass beidex
einmal auswerten , die Variable um eins inkrementieren und ein Ergebnis erhalten, das der Inhalt der Variablen nach der Auswertung ist.++x + 3
ist also nicht gleichx += 1 + 3
. Klammern Sie das einx += 1
und es ist identisch. Als Aussagen für sich sind sie identisch.++x + 3
,x += 1 + 3
oder(x += 1) + 3
haben das Verhalten nicht definiert (vorausgesetzt , der sich ergebende Wert „passt“).Um @ Pubby's Punkt etwas klarer zu machen, überlegen Sie sich
someObj.foo.bar.func(x, y, z).baz += 5
Ohne den
+=
Bediener gibt es zwei Möglichkeiten:someObj.foo.bar.func(x, y, z).baz = someObj.foo.bar.func(x, y, z).baz + 5
. Dies ist nicht nur furchtbar redundant und lang, sondern auch langsamer. Deshalb müsste mantmp := someObj.foo.bar.func(x, y, z); tmp.baz = tmp.bar + 5
. Das ist in Ordnung, aber für eine einfache Sache ist es viel Lärm. Dies ist eigentlich sehr ähnlich zu dem, was zur Laufzeit passiert, aber es ist mühsam zu schreiben und nur die Verwendung+=
wird die Arbeit auf den Compiler / Interpreter verlagern.Der Vorteil
+=
und anderer solcher Operatoren ist unbestreitbar, während es nur eine Frage der Zeit ist, sich an sie zu gewöhnen.quelle
Es ist wahr, dass es kürzer und einfacher ist, und es ist wahr, dass es wahrscheinlich von der zugrunde liegenden Assemblersprache inspiriert wurde, aber der Grund für die Best Practice ist, dass es eine ganze Klasse von Fehlern vermeidet und es einfacher macht, den Code zu überprüfen und sicher zu sein Was es macht.
Mit
Da es sich nur um einen Variablennamen handelt, sind Sie sicher, was die Anweisung bewirkt.
Mit
RidiculouslyComplexName = RidiculosulyComplexName + 1;
Es gibt immer Zweifel, dass die beiden Seiten genau gleich sind. Hast du den Bug gesehen? Noch schlimmer wird es, wenn Indizes und Qualifikatoren vorhanden sind.
quelle
Während die + = Notation idiomatisch und kürzer ist, sind dies nicht die Gründe, warum es leichter zu lesen ist. Der wichtigste Teil des Lesens von Code ist die Zuordnung der Syntax zur Bedeutung. Je genauer die Syntax mit den Gedankenprozessen des Programmierers übereinstimmt, desto besser lesbar ist sie (dies ist auch der Grund, warum Boilerplate-Code schlecht ist: Sie ist kein Teil des Gedankens Prozess, aber immer noch notwendig, damit der Code funktioniert). In diesem Fall lautet der Gedanke "Variable x um 5 erhöhen", nicht "x sei der Wert von x plus 5".
In anderen Fällen ist eine kürzere Schreibweise für die Lesbarkeit schlecht, z. B. wenn Sie einen ternären Operator verwenden, bei dem eine
if
Anweisung geeigneter wäre.quelle
Um zu verstehen, warum diese Operatoren zunächst in den Sprachen des C-Stils abgefasst sind, finden Sie hier einen Auszug aus K & R 1st Edition (1978) vor 34 Jahren:
Ich denke, aus dieser Passage geht hervor, dass Brian Kernighan und Dennis Ritchie (K & R) der Ansicht waren, dass Operatoren für die Zuweisung von Compounds die Lesbarkeit des Codes verbessern.
Es ist lange her, dass K & R das geschrieben hat, und seitdem haben sich viele der „Best Practices“ zum Schreiben von Code geändert oder weiterentwickelt. Mit dieser Frage zu programmers.stackexchange kann ich mich zum ersten Mal an jemanden erinnern, der eine Beschwerde über die Lesbarkeit von zusammengesetzten Zuweisungen geäußert hat. Ich frage mich also, ob viele Programmierer diese als Problem empfinden. Andererseits hat die Frage, während ich dies tippe, 95 positive Stimmen, so dass die Leute sie vielleicht beim Lesen von Code als irritierend empfinden.
quelle
Neben der Lesbarkeit machen sie tatsächlich verschiedene Dinge: Sie
+=
müssen den linken Operanden nicht zweimal auswerten.Zum Beispiel
expr = expr + 5
würdeexpr
zweimal auswerten (vorausgesetzt,expr
ist unrein).quelle
expr = expr + 5
undexpr += 5
expr
Nebenwirkungen vorliegen .expr
Nebenwirkungen auftreten,expr = expr + 5
müssen diese zweimal aufgerufen werden .volatile
Nebenwirkungen sind, undx=x+5
undx+=5
die gleichen Nebenwirkungen haben , wennx
istvolatile
Abgesehen von den offensichtlichen Vorteilen, die andere Leute sehr gut beschrieben haben, ist es kompakter, wenn Sie sehr lange Namen haben.
oder
quelle
Es ist prägnant.
Es ist viel kürzer zu tippen. Es sind weniger Bediener beteiligt. Es hat weniger Oberfläche und weniger Verwechslungsgefahr.
Es wird ein spezifischerer Operator verwendet.
Dies ist ein erfundenes Beispiel, und ich bin mir nicht sicher, ob tatsächliche Compiler dies implementieren. x + = y verwendet tatsächlich ein Argument und einen Operator und ändert x an Ort und Stelle. x = x + y könnte eine Zwischendarstellung von x = z haben, wobei z x + y ist. Letzterer verwendet zwei Operatoren, Addition und Zuweisung sowie eine temporäre Variable. Der einzelne Operator macht sehr deutlich, dass die Werteseite nichts anderes als y sein kann und nicht interpretiert werden muss. Und theoretisch könnte es eine ausgefallene CPU geben, die einen Plus-Gleichheitsoperator hat, der schneller läuft als ein Plus-Operator und einen Zuweisungsoperator in Reihe.
quelle
ADD
Anweisungen auf vielen CPUs haben Varianten, die direkt mit Registern oder Speicher arbeiten, wobei andere Register, Speicher oder Konstanten als zweites Addend verwendet werden. Es sind nicht alle Kombinationen verfügbar (z. B. Speicher zum Speicher hinzufügen), aber es gibt genug, um nützlich zu sein. In jedem Fall wird jeder Compiler mit einem anständigen Optimierer wissen, dass er den gleichen Codex = x + y
wie für generiertx += y
.Es ist eine schöne Sprache. Ob es schneller geht oder nicht, hängt von der Sprache ab. In C ist es schneller, da es sich um eine Anweisung zum Erhöhen der Variablen auf der rechten Seite handelt. Moderne Sprachen wie Python, Ruby, C, C ++ und Java unterstützen die Syntax op =. Es ist kompakt und man gewöhnt sich schnell daran. Da Sie es häufig im Code anderer Leute (OPC) sehen, können Sie sich auch daran gewöhnen und ihn verwenden. Hier ist, was in einigen anderen Sprachen passiert.
In Python führt das Eingeben
x += 5
immer noch zur Erstellung des Ganzzahlobjekts 1 (obwohl es möglicherweise aus einem Pool stammt) und zum Verwaisen des Ganzzahlobjekts mit 5.In Java kommt es zu einer stillschweigenden Umwandlung. Versuchen Sie es mit der Eingabe
quelle
x+=5
hat so wenig Bedeutung wiex=x+5
; Zum Beispiel in Haskell bewirkt Letzteres nicht, dassx
es um 5 inkrementiert wird - stattdessen entsteht eine unendliche Rekursionsschleife. Wer möchte eine Abkürzung dafür?+=
ist weniger sprachabhängig als prozessorabhängig . Beispielsweise ist X86 eine Architektur mit zwei Adressen, die nur+=
nativ unterstützt wird. Eine Aussage wiea = b + c;
muss kompiliert werden,a = b; a += c;
weil es einfach keine Anweisung gibt, die das Ergebnis der Addition irgendwo anders als an die Stelle eines der Summanden setzen kann. Im Gegensatz dazu ist die Power-Architektur eine Architektur mit drei Adressen, für die keine speziellen Befehle vorhanden sind+=
. Auf dieser Architektur kompilieren die Anweisungena += b;
unda = a + b;
immer den gleichen Code.Operatoren wie
+=
sind sehr nützlich, wenn Sie eine Variable als Akkumulator verwenden , dh eine laufende Summe:Ist viel einfacher zu lesen als:
Im ersten Fall ändern Sie konzeptionell den Wert in
x
. Im zweiten Fall berechnen Sie einen neuen Wert und weisen ihnx
jedem Mal zu. Und während Sie wahrscheinlich niemals Code schreiben würden, der so einfach ist, bleibt die Idee dieselbe ... Der Fokus liegt auf dem, was Sie mit einem vorhandenen Wert tun, anstatt einen neuen Wert zu schaffen.quelle
Bedenken Sie
Willst du wirklich schreiben?
quelle
Die anderen Antworten zielen auf die häufigsten Fälle ab, aber es gibt noch einen anderen Grund: In einigen Programmiersprachen kann es zu einer Überlastung kommen. zB Scala .
Kleine Scala-Lektion:
Wenn eine Klasse nur den
+
Operator definiert ,x+=y
ist das in der Tat eine Abkürzung vonx=x+y
.Überladungen einer Klasse
+=
sind jedoch nicht:Außerdem sind Operatoren
+
und+=
zwei separate Operatoren (und nicht nur diese: + a, ++ a, a ++, a + ba + = b sind ebenfalls verschiedene Operatoren); In Sprachen, in denen eine Überlastung des Operators vorliegt, kann dies zu interessanten Situationen führen. Genau wie oben beschrieben - wenn Sie den+
Operator überlasten , um das Hinzufügen durchzuführen, bedenken Sie, dass+=
auch dieser überlastet werden muss.quelle
+=
und dann zu definierena+b
, dass "eine Kopie von erstellta
,b
mit angelegt+=
und die Kopie von zurückgegeben wirda
".Sagen Sie es einmal und nur einmal:
x = x + 1
Ich sage zweimal 'x'.Aber schreibe niemals 'a = b + = 1', sonst müssen wir 10 Kätzchen, 27 Mäuse, einen Hund und einen Hamster töten.
Sie sollten den Wert einer Variablen niemals ändern, da dies den Nachweis der Code-Korrektheit erleichtert (siehe Funktionsprogrammierung). Wenn Sie dies jedoch tun, ist es besser, nichts nur einmal zu sagen.
quelle