Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

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:


Inhaltsverzeichnis

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 b in a, *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 *args einer Funktion, würde aber die weitere Verarbeitung des Ergebnisses erschweren.

Referenzen


Quelle: https://github.com/python/peps/blob/main/peps/pep-3132.rst

Zuletzt geändert: 2025-02-01 08:59:27 GMT