Warum gibt es keine ++
und --
Operatoren in Python?
Warum gibt es keine ++
und --
Operatoren in Python?
Antworten:
Es ist nicht, weil es keinen Sinn ergibt; Es ist durchaus sinnvoll, "x ++" als "x + = 1" zu definieren und die vorherige Bindung von x zu bewerten.
Wenn Sie den ursprünglichen Grund wissen möchten, müssen Sie entweder alte Python-Mailinglisten durchblättern oder jemanden fragen, der dort war (z. B. Guido), aber es ist leicht genug, dies nachträglich zu rechtfertigen:
Einfaches Inkrementieren und Dekrementieren ist nicht so erforderlich wie in anderen Sprachen. Sie schreiben nicht for(int i = 0; i < 10; ++i)
sehr oft Dinge wie in Python; stattdessen machst du Dinge wie for i in range(0, 10)
.
Da es nicht annähernd so oft benötigt wird, gibt es viel weniger Gründe, ihm eine eigene spezielle Syntax zu geben. Wenn Sie inkrementieren müssen, +=
ist in der Regel in Ordnung.
Es ist keine Entscheidung darüber, ob es sinnvoll ist oder ob es getan werden kann - es tut und es kann. Es ist eine Frage, ob der Nutzen es wert ist, zur Kernsyntax der Sprache hinzugefügt zu werden. Denken Sie daran, dies sind vier Operatoren - postinc, postdec, preinc, previous, und jeder dieser Operatoren müsste seine eigenen Klassenüberladungen haben. Sie müssen alle spezifiziert und getestet werden. es würde der Sprache Opcodes hinzufügen (was eine größere und daher langsamere VM-Engine impliziert); Jede Klasse, die ein logisches Inkrement unterstützt, müsste diese implementieren (zusätzlich zu +=
und -=
).
Dies ist alles überflüssig mit +=
und -=
, so würde es ein Nettoverlust werden.
i
direkt eine Schleife durchlaufen - wenn Sie es tatsächlich brauchen und nicht einfach zB verwenden könnenarray.append()
i++
und ++i
... stammten
++
und auf --
eine Weise verwendet wird, die zu undefinierten oder nicht spezifizierten Ergebnissen führt Verhalten. Sie ermöglichen es, komplizierten, schwer korrekt zu analysierenden Code zu schreiben.
Diese ursprüngliche Antwort, die ich geschrieben habe, ist ein Mythos aus der Folklore des Rechnens : Entlarvt von Dennis Ritchie als "historisch unmöglich", wie in den Briefen an die Herausgeber der Kommunikation der ACM vom Juli 2012 doi: 10.1145 / 2209249.2209251 vermerkt
Die C-Inkrementierungs- / Dekrementierungsoperatoren wurden zu einer Zeit erfunden, als der C-Compiler nicht sehr intelligent war und die Autoren die direkte Absicht angeben wollten, einen Maschinensprachenoperator zu verwenden, der eine Handvoll Zyklen für einen Compiler sparte, der könnte ein tun
load memory
load 1
add
store memory
anstatt
inc memory
und die PDP-11 noch unterstützt „Autoinkrement“ und „Autoinkrement latente“ Anweisungen entsprechend *++p
und *p++
, respectively. Siehe Abschnitt 5.3 des Handbuchs, wenn Sie schrecklich neugierig sind.
Da Compiler intelligent genug sind, um die in die Syntax von C integrierten allgemeinen Optimierungstricks zu verarbeiten, sind sie jetzt nur noch eine syntaktische Annehmlichkeit.
Python hat keine Tricks, um dem Assembler Absichten zu vermitteln, da es keine verwendet.
Ich habe immer angenommen, dass es mit dieser Linie des Python-Zen zu tun hat:
Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun.
x ++ und x + = 1 machen genau das Gleiche, es gibt also keinen Grund, beides zu haben.
one--
ist Null?
one--
ist eins im Satz, aber unmittelbar danach null. Dieses 'Koan' deutet also auch darauf hin, dass Inkrementierungs- / Dekrementierungsoperatoren nicht offensichtlich sind.
Natürlich könnten wir sagen "Guido hat sich gerade so entschieden", aber ich denke, die Frage betrifft wirklich die Gründe für diese Entscheidung. Ich denke, es gibt mehrere Gründe:
Weil in Python Ganzzahlen unveränderlich sind (int's + = gibt tatsächlich ein anderes Objekt zurück).
Außerdem müssen Sie sich mit ++ / - Gedanken über das Inkrementieren / Dekrementieren vor und nach dem Inkrementieren machen, und es ist nur noch ein Tastendruck erforderlich, um zu schreiben x+=1
. Mit anderen Worten, es vermeidet mögliche Verwirrung auf Kosten eines sehr geringen Gewinns.
42++
... zu generieren. So etwas (Ändern einer Literalkonstante) war in einigen alten Fortran-Compilern tatsächlich möglich (oder wie ich gelesen habe): Alle zukünftigen Verwendungen von diesem Literal in diesem Programmlauf hätte dann wirklich einen anderen Wert. Viel Spaß beim Debuggen!
int
Cs im Allgemeinen unveränderlich sind. Ein int
in C bezeichnet einfach einen Ort im Speicher. Und die Teile an diesem Ort sind sehr veränderlich. Sie können beispielsweise eine Referenz von erstellen int
und die Referenz dieser Referenz ändern. Diese Änderung ist in allen Verweisen (einschließlich der ursprünglichen int
Variablen) auf diesen Ort sichtbar . Das Gleiche gilt nicht für ein Python-Integer-Objekt.
Bei Python geht es viel um Klarheit, und kein Programmierer kann die Bedeutung wahrscheinlich richtig erraten, es --a
sei denn, er hat eine Sprache mit diesem Konstrukt gelernt.
Bei Python geht es auch viel darum , Konstrukte zu vermeiden, die zu Fehlern führen, und die ++
Operatoren sind bekanntermaßen reich an Fehlern. Diese beiden Gründe reichen aus, um diese Operatoren nicht in Python zu haben.
Die Entscheidung, dass Python Einrückungen zum Markieren von Blöcken anstelle von syntaktischen Mitteln wie einer Form von Anfangs- / Endklammerung oder obligatorischer Endmarkierung verwendet, basiert weitgehend auf denselben Überlegungen.
Schauen Sie sich zur Veranschaulichung die Diskussion um die Einführung eines bedingten Operators (in C :) cond ? resultif : resultelse
in Python im Jahr 2005 an. Lesen Sie mindestens die erste Nachricht und die Entscheidungsnachricht dieser Diskussion (die zuvor mehrere Vorläufer zum gleichen Thema hatte).
Wissenswertes: Das darin häufig erwähnte PEP ist das "Python Extension Proposal" PEP 308 . LC bedeutet Listenverständnis , GE bedeutet Generatorausdruck (und keine Sorge, wenn diese Sie verwirren, sind sie keine der wenigen komplizierten Stellen von Python).
Ich verstehe, warum Python keinen ++
Operator hat: Wenn Sie dies in Python schreiben, erhalten a=b=c=1
Sie drei Variablen (Beschriftungen), die auf dasselbe Objekt zeigen (welcher Wert 1 ist). Sie können dies überprüfen, indem Sie die ID-Funktion verwenden, die eine Objektspeicheradresse zurückgibt:
In [19]: id(a)
Out[19]: 34019256
In [20]: id(b)
Out[20]: 34019256
In [21]: id(c)
Out[21]: 34019256
Alle drei Variablen (Beschriftungen) zeigen auf dasselbe Objekt. Erhöhen Sie nun eine der Variablen und sehen Sie, wie sie sich auf die Speicheradressen auswirkt:
In [22] a = a + 1
In [23]: id(a)
Out[23]: 34019232
In [24]: id(b)
Out[24]: 34019256
In [25]: id(c)
Out[25]: 34019256
Sie können sehen, dass diese Variable a
jetzt als Variablen b
und auf ein anderes Objekt zeigt c
. Weil Sie es verwendet a = a + 1
haben, ist es ausdrücklich klar. Mit anderen Worten, Sie weisen der Beschriftung ein völlig anderes Objekt zu a
. Stellen Sie sich vor, Sie können schreiben, a++
dies würde darauf hindeuten, dass Sie der Variablen kein a
neues Objekt zugewiesen haben, sondern das alte Objekt inkrementeller erhöht haben. All dieses Zeug ist meiner Meinung nach zur Minimierung von Verwirrung. Zum besseren Verständnis sehen Sie, wie Python-Variablen funktionieren:
Ist Python Call-by-Value oder Call-by-Reference? Weder.
Übergibt Python nach Wert oder als Referenz?
Ist Python als Referenz oder als Wert übergeben?
Python: Wie übergebe ich eine Variable als Referenz?
Grundlegendes zu Python-Variablen und Speicherverwaltung
Emulieren des Pass-by-Value-Verhaltens in Python
Es wurde nur so entworfen. Inkrementierungs- und Dekrementierungsoperatoren sind nur Verknüpfungen für x = x + 1
. Python hat normalerweise eine Entwurfsstrategie angewendet, die die Anzahl alternativer Mittel zum Ausführen einer Operation reduziert. Die erweiterte Zuweisung kommt den Inkrementierungs- / Dekrementierungsoperatoren in Python am nächsten und wurde erst in Python 2.0 hinzugefügt.
return a[i++]
mit return a[i=i+1]
.
Ich bin sehr neu in Python, aber ich vermute, der Grund liegt in der Betonung zwischen veränderlichen und unveränderlichen Objekten innerhalb der Sprache. Jetzt weiß ich, dass x ++ leicht als x = x + 1 interpretiert werden kann, aber es sieht so aus, als würden Sie ein Objekt an Ort und Stelle inkrementieren, das unveränderlich sein könnte.
Nur meine Vermutung / Gefühl / Ahnung.
x++
ist näher an x += 1
als an x = x + 1
, diese beiden machen auch bei veränderlichen Objekten einen Unterschied.
Erstens wird Python nur indirekt von C beeinflusst; Es wird stark von ABC beeinflusst , das diese Operatoren anscheinend nicht hat. Daher sollte es keine große Überraschung sein, sie auch nicht in Python zu finden.
Zweitens werden, wie andere gesagt haben, Inkrementieren und Dekrementieren von +=
und -=
bereits unterstützt.
Drittens umfasst die vollständige Unterstützung eines ++
und eines --
Operator-Sets normalerweise die Unterstützung sowohl der Präfix- als auch der Postfix-Version. In C und C ++ kann dies zu allen Arten von "schönen" Konstrukten führen, die (für mich) gegen den Geist der Einfachheit und Geradlinigkeit zu sein scheinen, den Python umfasst.
Während die C-Anweisung while(*t++ = *s++);
für einen erfahrenen Programmierer einfach und elegant erscheint, ist sie für jemanden, der sie lernt, alles andere als einfach. Wenn Sie eine Mischung aus Präfix- und Postfix-Inkrementen und -Dekrementen verwenden, müssen selbst viele Profis innehalten und ein wenig nachdenken.
Ich glaube, es ergibt sich aus dem Python-Credo, dass "explizit besser ist als implizit".
Dies mag daran liegen, dass @GlennMaynard die Angelegenheit im Vergleich zu anderen Sprachen betrachtet, aber in Python tun Sie die Dinge auf Python-Weise. Es ist keine "Warum" -Frage. Es ist da und Sie können Dinge mit dem gleichen Effekt tun x+=
. Im Zen von Python heißt es: "Es sollte nur einen Weg geben, ein Problem zu lösen." Mehrfachauswahl ist in der Kunst großartig (Meinungsfreiheit), aber in der Technik mies.
Die ++
Klasse der Operatoren sind Ausdrücke mit Nebenwirkungen. Dies ist etwas, das in Python im Allgemeinen nicht zu finden ist.
Aus dem gleichen Grund ist eine Zuweisung in Python kein Ausdruck, wodurch die allgemeine if (a = f(...)) { /* using a here */ }
Redewendung verhindert wird.
Schließlich vermute ich, dass dort Operatoren nicht sehr konsistent mit Pythons Referenzsemantik sind. Denken Sie daran, dass Python keine Variablen (oder Zeiger) mit der aus C / C ++ bekannten Semantik hat.
f(a)
Wo a
ist eine Liste, ein unveränderliches Objekt.
Vielleicht wäre eine bessere Frage zu fragen, warum diese Operatoren in C existieren. K & R nennt Inkrementierungs- und Dekrementierungsoperatoren "ungewöhnlich" (Abschnitt 2.8, Seite 46). Die Einleitung nennt sie "prägnanter und oft effizienter". Ich vermute, dass die Tatsache, dass diese Operationen immer bei der Zeigermanipulation auftreten, auch bei ihrer Einführung eine Rolle gespielt hat. In Python wurde wahrscheinlich entschieden, dass es keinen Sinn macht, zu versuchen, Inkremente zu optimieren (tatsächlich habe ich gerade einen Test in C durchgeführt, und es scheint, dass die von gcc generierte Assembly in beiden Fällen addl anstelle von include verwendet), und es gibt keine Zeigerarithmetik; Es wäre also nur eine weitere Möglichkeit gewesen, und wir wissen, dass Python das verabscheut.
so wie ich es verstanden habe, wirst du nicht denken, dass der Wert im Speicher geändert wird. Wenn Sie in c x ++ ausführen, ändert sich der Wert von x im Speicher. aber in Python sind alle Zahlen unveränderlich, daher hat die Adresse, auf die x zeigte, immer noch x, nicht x + 1. Wenn Sie x ++ schreiben, denken Sie, dass x ändern, was wirklich passiert, ist, dass x-Aktualisierung in einen Speicherort geändert wird, in dem x + 1 gespeichert ist, oder erstellen Sie diesen Speicherort neu, wenn doe nicht vorhanden ist.
++
unterscheidet das also von += 1
?
Um bereits gute Antworten auf dieser Seite zu vervollständigen:
Nehmen wir an, wir entscheiden uns dafür, prefix ( ++i
), das die unären + und - Operatoren brechen würde.
Heutzutage wird ein Präfix von ++
oder --
nichts ausgeführt, da der unäre Plus-Operator zweimal (nichts) oder der unäre minus zweimal (zweimal: bricht sich selbst ab) aktiviert wird.
>>> i=12
>>> ++i
12
>>> --i
12
Das würde diese Logik möglicherweise brechen.
Andere Antworten haben beschrieben, warum es für Iteratoren nicht benötigt wird, aber manchmal ist es nützlich, wenn Sie eine Variable inline zuweisen, um sie zu erhöhen. Sie können den gleichen Effekt mit Tupeln und Mehrfachzuweisungen erzielen:
b = ++a
wird:
a,b = (a+1,)*2
und b = a++
wird:
a,b = a+1, a
3.8 Python stellt die Zuordnung :=
Betreiber, so dass wir erreichen foo(++a)
mit
foo(a:=a+1)
foo(a++)
ist aber immer noch schwer fassbar.
Ich denke, dies bezieht sich auf die Konzepte der Veränderlichkeit und Unveränderlichkeit von Objekten. 2,3,4,5 sind in Python unveränderlich. Siehe das Bild unten. 2 hat die ID bis zu diesem Python-Prozess festgelegt.
x ++ würde im Wesentlichen ein In-Place-Inkrement wie C bedeuten. In C führt x ++ In-Place-Inkremente durch. X = 3 und x ++ würden also 3 im Speicher auf 4 erhöhen, im Gegensatz zu Python, wo 3 noch im Speicher vorhanden wäre.
Daher müssen Sie in Python keinen Wert im Speicher neu erstellen. Dies kann zu Leistungsoptimierungen führen.
Dies ist eine auf Ahnung basierende Antwort.
Ich weiß, dass dies ein alter Thread ist, aber der häufigste Anwendungsfall für ++ i wird nicht behandelt, nämlich das manuelle Indizieren von Sets, wenn keine Indizes bereitgestellt werden. In dieser Situation bietet Python enumerate ()
Beispiel: Wenn Sie in einer bestimmten Sprache ein Konstrukt wie foreach verwenden, um über eine Menge zu iterieren, sagen wir für das Beispiel sogar, dass es sich um eine ungeordnete Menge handelt, und Sie benötigen einen eindeutigen Index für alles, um sie voneinander zu unterscheiden
i = 0
stuff = {'a': 'b', 'c': 'd', 'e': 'f'}
uniquestuff = {}
for key, val in stuff.items() :
uniquestuff[key] = '{0}{1}'.format(val, i)
i += 1
In solchen Fällen bietet Python eine Aufzählungsmethode, z
for i, (key, val) in enumerate(stuff.items()) :