PEP 3114 – Umbenennung von iterator.next() in iterator.__next__()
- Autor:
- Ka-Ping Yee <ping at zesty.ca>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 04.03.2007
- Python-Version:
- 3.0
- Post-History:
Zusammenfassung
Das Iterator-Protokoll in Python 2.x besteht aus zwei Methoden: __iter__(), die auf einem iterierbaren Objekt aufgerufen wird, um einen Iterator zu liefern, und next(), die auf einem Iterator-Objekt aufgerufen wird, um das nächste Element in der Sequenz zu liefern. Die Verwendung einer for-Schleife, um über ein iterierbares Objekt zu iterieren, ruft implizit beide dieser Methoden auf. Dieser PEP schlägt vor, dass die next-Methode in __next__ umbenannt wird, konsistent mit allen anderen Protokollen in Python, bei denen eine Methode implizit als Teil eines sprachlichen Protokolls aufgerufen wird, und dass eine eingebaute Funktion namens next eingeführt wird, um die __next__-Methode aufzurufen, konsistent mit der Art und Weise, wie andere Protokolle explizit aufgerufen werden.
Namen mit doppelten Unterstrichen
In Python werden doppelte Unterstriche vor und nach einem Namen verwendet, um Namen zu unterscheiden, die zur Sprache selbst gehören. Attribute und Methoden, die vom Interpreter implizit verwendet oder erstellt werden, verwenden diese Namenskonvention; einige Beispiele sind
__file__– ein vom Interpreter automatisch erstelltes Attribut__dict__– ein Attribut mit besonderer Bedeutung für den Interpreter__init__– eine vom Interpreter implizit aufgerufene Methode
Beachten Sie, dass diese Konvention für Methoden wie __init__ gilt, die vom Programmierer explizit definiert werden, sowie für Attribute wie __file__, die nur durch explizite Benennung zugänglich sind. Sie umfasst also Namen, die vom Interpreter verwendet *oder* erstellt werden.
(Nicht alles, was als „Protokoll“ bezeichnet wird, besteht aus Methoden mit Namen, die doppelte Unterstriche enthalten. Beispielsweise hat die Methode __contains__ doppelte Unterstriche, da der Sprachkonstrukt x in y implizit __contains__ aufruft. Aber obwohl die Methode read Teil des Dateiprotokolls ist, hat sie keine doppelten Unterstriche, da es keinen Sprachkonstrukt gibt, der x.read() implizit aufruft.)
Die Verwendung von doppelten Unterstrichen schafft einen separaten Namensraum für Namen, die Teil der Python-Sprachdefinition sind, sodass Programmierer Variablen, Attribute und Methoden, die mit Buchstaben beginnen, frei erstellen können, ohne Angst vor stillen Kollisionen mit Namen mit sprachdefinierter Bedeutung haben zu müssen. (Kollisionen mit reservierten Schlüsselwörtern sind immer noch ein Problem, aber zumindest führt dies sofort zu einem Syntaxfehler.)
Die Benennung der next-Methode für Iteratoren ist eine Ausnahme von dieser Konvention. Code, der nirgendwo einen expliziten Aufruf einer next-Methode enthält, kann dennoch stillschweigend durch die Anwesenheit einer solchen Methode beeinflusst werden. Daher schlägt dieser PEP vor, dass Iteratoren stattdessen eine __next__-Methode anstelle einer next-Methode haben sollten (ohne Änderung der Semantik).
Methoden und eingebaute Funktionen mit doppelten Unterstrichen
Die Python-Sprache definiert mehrere Protokolle, die durch die Definition von Methoden mit doppelten Unterstrichen implementiert oder angepasst werden. In jedem Fall wird das Protokoll von einer internen Methode bereitgestellt, die als C-Funktion im Interpreter implementiert ist. Für in Python definierte Objekte unterstützt diese C-Funktion die Anpassung durch implizites Aufrufen einer Python-Methode mit doppeltem Unterstrichnamen (sie führt oft zusätzlich zur reinen Aufrufung der Python-Methode noch kleine zusätzliche Arbeiten aus).
Manchmal wird das Protokoll durch eine syntaktische Konstruktion aufgerufen
x[y]–> internertp_getitem–>x.__getitem__(y)x + y–> internernb_add–>x.__add__(y)-x–> internernb_negative–>x.__neg__()
Manchmal gibt es keine syntaktische Konstruktion, aber es ist dennoch nützlich, das Protokoll explizit aufrufen zu können. Für solche Fälle bietet Python eine eingebaute Funktion mit demselben Namen, aber ohne die doppelten Unterstriche.
len(x)–> internesq_length–>x.__len__()hash(x)–> internetp_hash–>x.__hash__()iter(x)–> internetp_iter–>x.__iter__()
Nach diesem Muster ist der natürliche Weg, next zu behandeln, die Hinzufügung einer eingebauten Funktion next, die sich genau gleich verhält.
next(x)–> internetp_iternext–>x.__next__()
Darüber hinaus wird vorgeschlagen, dass die eingebaute Funktion next einen Sentinel-Wert als optionales zweites Argument akzeptiert, im Stil der eingebauten Funktionen getattr und iter. Wenn next mit zwei Argumenten aufgerufen wird, fängt sie die StopIteration-Ausnahme ab und gibt stattdessen den Sentinel-Wert zurück, anstatt die Ausnahme weiterzuleiten. Dies schafft eine schöne Dualität zwischen iter und next.
iter(function, sentinel) <–> next(iterator, sentinel)
Vorherige Vorschläge
Dieser Vorschlag ist keine neue Idee. Die hier vorgeschlagene Idee wurde vom BDFL auf python-dev [1] unterstützt und wird sogar im ursprünglichen Iterator-PEP, PEP 234, erwähnt.
(In retrospect, it might have been better to go for __next__()
and have a new built-in, next(it), which calls it.__next__().
But alas, it's too late; this has been deployed in Python 2.2
since December 2001.)
Einwände
Es gab einige Einwände gegen die Hinzufügung weiterer eingebauter Funktionen. Insbesondere schreibt Martin von Loewis [2]
I dislike the introduction of more builtins unless they have a true
generality (i.e. are likely to be needed in many programs). For this
one, I think the normal usage of __next__ will be with a for loop, so
I don't think one would often need an explicit next() invocation.
It is also not true that most protocols are explicitly invoked through
builtin functions. Instead, most protocols are can be explicitly invoked
through methods in the operator module. So following tradition, it
should be operator.next.
...
As an alternative, I propose that object grows a .next() method,
which calls __next__ by default.
Migrationsplan
Zwei zusätzliche Transformationen werden dem 2to3-Übersetzungstool hinzugefügt [3]
- Methodendefinitionen namens
nextwerden in__next__umbenannt. - Explizite Aufrufe der
next-Methode werden durch Aufrufe der eingebautennext-Funktion ersetzt. Zum Beispiel wird ausx.next()next(x).
Collin Winter untersuchte die Möglichkeit, automatisch zu entscheiden, ob die zweite Transformation durchgeführt werden soll, abhängig von der Anwesenheit einer Modul-Ebene-Bindung an next [4] und fand heraus, dass es „hässlich und langsam“ wäre. Stattdessen gibt das Übersetzungstool Warnungen aus, wenn eine solche Bindung erkannt wird. Collin hat Warnungen für die folgenden Bedingungen vorgeschlagen [5]
- Modul-Ebene-Zuweisungen zu
next. - Modul-Ebene-Definitionen einer Funktion namens
next. - Modul-Ebene-Importe des Namens
next. - Zuweisungen an
__builtin__.next.
Genehmigung
Dieser PEP wurde von Guido am 6. März 2007 akzeptiert [6].
Implementierung
Ein Patch mit den notwendigen Änderungen (außer dem 2to3-Tool) wurde von Georg Brandl geschrieben und als Revision 54910 eingepflegt.
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-3114.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT