PEP 284 – Integer for-loops
- Autor:
- David Eppstein <eppstein at ics.uci.edu>, Gregory Ewing <greg.ewing at canterbury.ac.nz>
- Status:
- Abgelehnt
- Typ:
- Standards Track
- Erstellt:
- 01-März 2002
- Python-Version:
- 2.3
- Post-History:
Inhaltsverzeichnis
Zusammenfassung
Dieser PEP schlägt vor, die Iteration über Integer-Intervalle zu vereinfachen, indem der Bereich der Ausdrücke nach dem Schlüsselwort „for“ erweitert wird, um Drei-Wege-Vergleiche wie
for lower <= var < upper:
anstelle der aktuellen
for item in list:
Syntax zu erlauben. Die resultierende Schleife oder Listeniteration durchläuft alle Werte von var, die den Vergleich wahr machen, beginnend mit dem linken Endpunkt des gegebenen Intervalls.
Bekanntmachung
Dieser PEP wird abgelehnt. Es gab eine Reihe von behebaren Problemen mit dem Vorschlag (siehe die Korrekturen in Raymond Hettingers python-dev-Post vom 18. Juni 2005 [1]). Selbst mit den Korrekturen erhielt der Vorschlag keine Unterstützung. Insbesondere Guido stimmte der Prämisse nicht zu, dass das range()-Format behoben werden musste: „Der Sinn (vor 15 Jahren) von range() war es, keine Syntax für eine Schleife über Zahlen zu benötigen. Ich denke, das hat gut funktioniert und es gibt nichts, was behoben werden muss (außer dass range() ein Iterator werden muss, was es in Python 3.0 tun wird).“
Begründung
Eine der häufigsten Verwendungen von for-Schleifen in Python ist die Iteration über ein Integer-Intervall. Python stellt die Funktionen range() und xrange() zur Erzeugung von Listen und Iteratoren für solche Intervalle bereit, die für den häufigsten Fall am besten geeignet sind: halboffene Intervalle, die von Null ansteigen. Die range()-Syntax ist jedoch für offene oder geschlossene Intervalle umständlicher und es mangelt ihr an Symmetrie beim Umkehren der Iterationsreihenfolge. Darüber hinaus macht der Aufruf einer ungewohnten Funktion es für Neueinsteiger in Python schwierig, Code zu verstehen, der range() oder xrange() verwendet.
Der wahrgenommene Mangel an einer natürlichen, intuitiven Syntax für Integer-Iteration hat zu hitzigen Debatten auf der python-list geführt und mindestens vier PEPs vor dieser hervorgebracht. PEP 204 (abgelehnt) schlug vor, die Python-Slice-Syntax für Integer-Bereiche wiederzuverwenden, was zu einer kürzeren Syntax führte, aber das Lesbarkeitsproblem von range() mit mehreren Argumenten nicht löste. PEP 212 (zurückgestellt) schlug mehrere Syntaxen für die direkte Konvertierung einer Liste in eine Sequenz von Integer-Indizes vor, anstelle des aktuellen Idioms
range(len(list))
für eine solche Konvertierung, und PEP 281 schlägt vor, dasselbe Idiom zu vereinfachen, indem es als
range(list).
geschrieben werden kann. PEP 276 schlägt die automatische Konvertierung von Integern in Iteratoren vor, was den häufigsten halboffenen Fall vereinfacht, aber nicht die Komplexität anderer Arten von Intervallen adressiert. Zusätzliche Alternativen wurden auf der python-list diskutiert.
Die hier beschriebene Lösung besteht darin, einen Drei-Wege-Vergleich nach dem Schlüsselwort „for“ sowohl im Kontext einer for-Schleife als auch einer Listenkomprehension zu erlauben.
for lower <= var < upper:
Dies würde eine Iteration über ein Intervall von aufeinanderfolgenden Integern bewirken, beginnend mit der linken Grenze im Vergleich und endend mit der rechten Grenze. Die genauen Vergleichsoperationen würden bestimmen, ob das Intervall an einem oder beiden Enden offen oder geschlossen ist und ob die Integer in aufsteigender oder absteigender Reihenfolge betrachtet werden.
Diese Syntax entspricht eng der mathematischen Standardnotation und ist daher für Python-Neulinge wahrscheinlich vertrauter als die aktuelle range()-Syntax. Offene und geschlossene Intervallgrenzen sind gleichermaßen einfach auszudrücken, und die Umkehrung eines Integer-Intervalls kann einfach durch Vertauschen der beiden Grenzen und Umkehren der Vergleiche gebildet werden. Darüber hinaus würden die Semantik einer solchen Schleife eng einer Interpretation der bestehenden Python for-Schleifen ähneln.
for item in list
iteriert über genau die Werte von item, die den Ausdruck
item in list
wahr machen. Ebenso würde das neue Format
for lower <= var < upper:
über genau die Integer-Werte von var iterieren, die den Ausdruck
lower <= var < upper
wahr machen.
Spezifikation
Wir schlagen vor, die Syntax einer for-Anweisung zu erweitern, derzeit
for_stmt: "for" target_list "in" expression_list ":" suite
["else" ":" suite]
wie unten beschrieben
for_stmt: "for" for_test ":" suite ["else" ":" suite]
for_test: target_list "in" expression_list |
or_expr less_comp or_expr less_comp or_expr |
or_expr greater_comp or_expr greater_comp or_expr
less_comp: "<" | "<="
greater_comp: ">" | ">="
Ebenso schlagen wir vor, die Syntax von Listenkomprehensionen zu erweitern, derzeit
list_for: "for" expression_list "in" testlist [list_iter]
und ersetzt durch
list_for: "for" for_test [list_iter]
In allen Fällen unterliegt der durch for_test gebildete Ausdruck den gleichen Präzedenzregeln wie Vergleiche in Ausdrücken. Die beiden comp_operators in einem for_test müssen beide vom gleichen Typ sein, im Gegensatz zu verketteten Vergleichen in Ausdrücken, die keine solche Einschränkung haben.
Wir bezeichnen die beiden or_expr auf der linken und rechten Seite der for-Schleifen-Syntax als Grenzen der Schleife und das mittlere or_expr als Variable der Schleife. Wenn eine for-Schleife mit der neuen Syntax ausgeführt wird, werden die Ausdrücke für beide Grenzen ausgewertet und ein Iterator-Objekt erstellt, das durch alle Integer zwischen den beiden Grenzen gemäß den verwendeten Vergleichsoperationen iteriert. Der Iterator beginnt mit einer Ganzzahl, die gleich oder nahe der linken Grenze ist, und durchläuft dann die restlichen Ganzzahlen mit einer Schrittgröße von +1 oder -1, wenn die Vergleichsoperation in der durch less_comp bzw. greater_comp beschriebenen Menge enthalten ist. Die Ausführung wird dann fortgesetzt, als ob der Ausdruck gewesen wäre
for variable in iterator
wobei „variable“ sich auf die Variable der Schleife bezieht und „iterator“ sich auf den für das gegebene Integer-Intervall erstellten Iterator bezieht.
Die Werte, die die Schleifenvariable in einer Integer-for-Schleife annimmt, können je nach Größe der Grenzen entweder normale Integer oder lange Integer sein. Beide Grenzen einer Integer-for-Schleife müssen zu einem reellen numerischen Typ (Integer, Long oder Float) ausgewertet werden. Jeder andere Wert führt dazu, dass die for-Schleifenanweisung eine TypeError-Ausnahme auslöst.
Probleme
Die folgenden Probleme wurden in der Diskussion dieses und verwandter Vorschläge in der Python-Liste aufgeworfen.
- Sollte die rechte Grenze einmal oder jedes Mal in der Schleife ausgewertet werden? Offensichtlich ist es nur sinnvoll, die linke Grenze einmal auszuwerten. Aus Gründen der Konsistenz und Effizienz haben wir die gleiche Konvention für die rechte Grenze gewählt.
- Obwohl die neue Syntax Integer-for-Schleifen erheblich vereinfacht, sind Listenkomprehensionen mit der neuen Syntax nicht so einfach. Wir sind der Meinung, dass dies angemessen ist, da for-Schleifen häufiger vorkommen als Komprehensionen.
- Der Vorschlag erlaubt keinen Zugriff auf Integer-Iterator-Objekte, wie sie von
xrangeerstellt würden. Das stimmt, aber wir sehen dies als Mangel in der allgemeinen Syntax für Listenkomprehensionen, der über den Rahmen dieses Vorschlags hinausgeht. Außerdem wirdxrange()weiterhin verfügbar sein. - Der Vorschlag erlaubt keine anderen Inkremente als 1 und -1. Allgemeinere arithmetische Progressionen müssten mit
range()oderxrange()oder durch eine Syntax für Listenkomprehensionen wie[2*x for 0 <= x <= 100]
- erstellt werden. Die Position der Schleifenvariable in der Mitte eines Drei-Wege-Vergleichs ist nicht so offensichtlich wie die Variable in der aktuellen
for item in list
Syntax, was zu einem möglichen Verlust an Lesbarkeit führt. Wir sind der Meinung, dass dieser Verlust durch die Zunahme der Lesbarkeit durch eine natürliche Integer-Iterationssyntax aufgewogen wird.
- Bis zu einem gewissen Grad befasst sich dieser PEP mit denselben Problemen wie PEP 276. Wir sind der Meinung, dass sich die beiden PEPs nicht widersprechen, da sich PEP 276 hauptsächlich mit halboffenen Bereichen ab 0 (dem einfachen Fall von
range()) befasst, während sich dieser PEP hauptsächlich mit der Vereinfachung aller anderen Fälle befasst. Wenn dieser PEP jedoch genehmigt wird, könnte seine neue, einfachere Syntax für Integer-Schleifen die Motivation für PEP 276 bis zu einem gewissen Grad verringern. - Es ist nicht klar, ob es sinnvoll ist, Gleitkommazahlen als Grenzen für eine Integer-Schleife zuzulassen: Wenn eine Gleitkommazahl einen ungenauen Wert darstellt, wie kann sie dann zur Bestimmung einer exakten Sequenz von Integern verwendet werden? Andererseits würde das Verbot von Gleitkommazahl-Grenzen die Verwendung von
floor()undceiling()in Integer-for-Schleifen erschweren, da es auch mitrange()schwierig ist. Wir haben uns für Flexibilität entschieden, aber dies kann zu einigen Implementierungsschwierigkeiten bei der Bestimmung der kleinsten und größten Integer-Werte führen, die einen gegebenen Vergleich wahr machen. - Sollten andere Typen als int, long und float als Grenzen zugelassen werden? Eine andere Wahl wäre, alle Grenzen mit
int()in Integer zu konvertieren und alles zuzulassen, was so konvertiert werden kann, anstelle von nur Gleitkommazahlen. Dies würde jedoch die Semantik ändern:0.3 <= xist nicht dasselbe wieint(0.3) <= x, und es wäre verwirrend, wenn eine Schleife mit 0.3 als untere Grenze bei Null beginnt. Außerdem kannint(f)im Allgemeinen sehr weit vonfentfernt sein.
Implementierung
Eine Implementierung ist derzeit nicht verfügbar. Die Implementierung wird voraussichtlich keine großen Schwierigkeiten bereiten: Die neue Syntax könnte bei Bedarf erkannt werden, indem ein allgemeiner Ausdruck nach jedem Schlüsselwort „for“ geparst und getestet wird, ob die höchste Operation des Ausdrucks „in“ oder ein Drei-Wege-Vergleich ist. Der Python-Compiler würde jede Instanz der neuen Syntax in eine Schleife über die Elemente eines speziellen Iterator-Objekts umwandeln.
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0284.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT