PEP 3132 – Erweiterte Iterable-Entpackung
- Autor:
- Georg Brandl <georg at python.org>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 30. Apr. 2007
- Python-Version:
- 3.0
- Post-History:
Zusammenfassung
Dieses PEP schlägt eine Änderung der Syntax zur Entpackung von Iterables vor, die es ermöglicht, einen "Catch-all"-Namen anzugeben, dem eine Liste aller Elemente zugewiesen wird, die keinem "regulären" Namen zugewiesen wurden.
Ein Beispiel sagt mehr als tausend Worte
>>> a, *b, c = range(5)
>>> a
0
>>> c
4
>>> b
[1, 2, 3]
Begründung
Viele Algorithmen erfordern die Aufteilung einer Sequenz in ein "erste, restliche" Paar. Mit der neuen Syntax,
first, rest = seq[0], seq[1:]
wird durch die sauberere und wahrscheinlich effizientere ersetzt
first, *rest = seq
Für komplexere Entpackungsmuster sieht die neue Syntax noch sauberer aus und die umständliche Indexbehandlung ist nicht mehr notwendig.
Außerdem, wenn der Wert auf der rechten Seite keine Liste, sondern ein Iterable ist, muss er zuerst in eine Liste konvertiert werden, um Slicing durchführen zu können; um die Erstellung dieser temporären Liste zu vermeiden, muss man zu
it = iter(seq)
first = it.next()
rest = list(it)
Spezifikation
Ein Tupel (oder eine Liste) auf der linken Seite einer einfachen Zuweisung (Entpackung ist für erweiterte Zuweisung nicht definiert) darf höchstens einen Ausdruck enthalten, dem ein einzelnes Sternchen vorangestellt ist (dieser wird fortan als "gestefter" Ausdruck bezeichnet, während die anderen Ausdrücke in der Liste als "obligatorisch" bezeichnet werden). Dies bezeichnet einen Unterausdruck, dem eine Liste aller Elemente aus dem entpackten Iterable zugewiesen wird, die keinen der obligatorischen Ausdrücke zugewiesen wurden, oder eine leere Liste, wenn keine solchen Elemente vorhanden sind.
Zum Beispiel, wenn seq eine durch Slicing zugängliche Sequenz ist, sind alle folgenden Zuweisungen äquivalent, wenn seq mindestens zwei Elemente hat
a, b, c = seq[0], list(seq[1:-1]), seq[-1]
a, *b, c = seq
[a, *b, c] = seq
Es ist ein Fehler (wie es derzeit der Fall ist), wenn das Iterable nicht genügend Elemente enthält, um allen obligatorischen Ausdrücken zugewiesen zu werden.
Es ist auch ein Fehler, den gesteften Ausdruck als alleiniges Zuweisungsziel zu verwenden, wie in
*a = range(5)
Dies ist jedoch gültige Syntax
*a, = range(5)
Beachten Sie, dass dieser Vorschlag auch für Tupel im impliziten Zuweisungskontext gilt, wie z. B. in einer for-Anweisung
for a, *b in [(1, 2, 3), (4, 5, 6, 7)]:
print(b)
würde ausgeben
[2, 3]
[5, 6, 7]
Gesteifte Ausdrücke sind nur als Zuweisungsziele erlaubt, ihre Verwendung an anderer Stelle (außer natürlich bei Star-Args in Funktionsaufrufen) ist ein Fehler.
Implementierung
Grammatikänderung
Diese Funktion erfordert eine neue Grammatikregel
star_expr: ['*'] expr
In diesen beiden Regeln wird expr zu star_expr geändert
comparison: star_expr (comp_op star_expr)*
exprlist: star_expr (',' star_expr)* [',']
Änderungen am Compiler
Ein neuer ASDL-Ausdruckstyp Starred wird hinzugefügt, der einen gesteften Ausdruck darstellt. Beachten Sie, dass das hier eingeführte gestefte Ausdruckselement universell ist und später für andere Zwecke im Nicht-Zuweisungskontext verwendet werden könnte, wie z. B. der yield *iterable-Vorschlag.
Der Compiler wird geändert, um alle Fälle zu erkennen, in denen ein gestefter Ausdruck ungültig ist, und diese mit Syntaxfehlern zu kennzeichnen.
Eine neue Bytecode-Anweisung, UNPACK_EX, wird hinzugefügt, deren Argument die Anzahl der obligatorischen Ziele vor dem gesteften Ziel in den unteren 8 Bits und die Anzahl der obligatorischen Ziele nach dem gesteften Ziel in den oberen 8 Bits enthält. Zum Entpacken von Sequenzen ohne gesteifte Ausdrücke bleibt der alte UNPACK_ITERABLE-Opcode erhalten.
Änderungen am Bytecode-Interpreter
Die Funktion unpack_iterable() in ceval.c wird geändert, um die erweiterte Entpackung über einen Parameter argcntafter zu handhaben. Im Fall von UNPACK_EX wird die Funktion Folgendes tun:
- Sammeln aller Elemente für obligatorische Ziele vor dem gesteften
- Sammeln aller verbleibenden Elemente aus dem Iterable in einer Liste
- Entfernen von Elementen für obligatorische Ziele nach dem gesteften aus der Liste
- Drücken der einzelnen Elemente und der geänderten Liste auf den Stack
Es können Abkürzungen für das Entpacken von Iterables bekannter Typen wie Listen oder Tupeln hinzugefügt werden.
Die aktuelle Implementierung ist im SourceForge Patch Tracker [SFPATCH] zu finden. Sie enthält nun einen minimalen Testfall.
Akzeptanz
Nach einer kurzen Diskussion auf der python-3000-Liste [1] wurde das PEP in seiner jetzigen Form von Guido akzeptiert. Diskutierte mögliche Änderungen waren
- Nur einen gesteften Ausdruck als letztes Element in der exprlist zulassen. Dies würde den Entpackungscode etwas vereinfachen und es ermöglichen, dass der gestefte Ausdruck ein Iterator zugewiesen bekommt. Dieses Verhalten wurde abgelehnt, da es zu überraschend wäre.
- Versuchen, dem gesteften Ziel den gleichen Typ wie dem Quell-Iterable zu geben, z. B. wäre
bina, *b = 'hello'der String'ello'zugewiesen. Dies mag nett erscheinen, lässt sich aber bei allen Iterables nicht konsistent richtig umsetzen. - Das gestefte Ziel als Tupel statt als Liste machen. Dies wäre konsistent mit den
*argseiner Funktion, würde aber die weitere Verarbeitung des Ergebnisses erschweren.
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-3132.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT