PEP 3152 – Cofunktionen
- Autor:
- Gregory Ewing <greg.ewing at canterbury.ac.nz>
- Status:
- Abgelehnt
- Typ:
- Standards Track
- Erstellt:
- 13-Feb-2009
- Python-Version:
- 3.3
- Post-History:
Zusammenfassung
Es wird eine Syntax vorgeschlagen, um eine spezielle Art von Generator namens „Cofunktion“ zu definieren und aufzurufen. Sie wurde entwickelt, um eine optimierte Möglichkeit zum Schreiben von generatorbasierten Coroutinen bereitzustellen und die frühzeitige Erkennung bestimmter Fehlerarten zu ermöglichen, die beim Schreiben solcher Codes leicht auftreten können und sonst zu schwer zu diagnostizierenden Symptomen führen.
Dieser Vorschlag baut auf dem in PEP 380 beschriebenen Mechanismus „yield from“ auf und beschreibt einige der Semantiken von Cofunktionen in Bezug darauf. Es wäre jedoch möglich, Cofunktionen unabhängig von PEP 380 zu definieren und zu implementieren, wenn dies gewünscht wird.
Ablehnung
Siehe https://mail.python.org/pipermail/python-dev/2015-April/139503.html
Spezifikation
Cofunktionsdefinitionen
Ein neues Schlüsselwort codef wird eingeführt, das anstelle von def zur Definition einer Cofunktion verwendet wird. Eine Cofunktion ist eine spezielle Art von Generator mit folgenden Merkmalen:
- Eine Cofunktion ist immer ein Generator, auch wenn sie keine
yieldoderyield fromAusdrücke enthält. - Eine Cofunktion kann nicht auf die gleiche Weise wie eine gewöhnliche Funktion aufgerufen werden. Eine Ausnahme wird ausgelöst, wenn ein gewöhnlicher Aufruf einer Cofunktion versucht wird.
Cocal
Aufrufe von einer Cofunktion zu einer anderen erfolgen durch Kennzeichnung des Aufrufs mit einem neuen Schlüsselwort cocall. Der Ausdruck
cocall f(*args, **kwds)
ist semantisch äquivalent zu
yield from f.__cocall__(*args, **kwds)
mit der Ausnahme, dass das von __cocall__ zurückgegebene Objekt ein Iterator sein soll, sodass der Schritt des Aufrufs von iter() darauf übersprungen wird.
Die vollständige Syntax eines Cocall-Ausdrucks wird durch die folgenden Grammatikzeilen beschrieben:
atom: cocall | <existing alternatives for atom>
cocall: 'cocall' atom cotrailer* '(' [arglist] ')'
cotrailer: '[' subscriptlist ']' | '.' NAME
Das Schlüsselwort cocall ist nur innerhalb einer Cofunktion syntaktisch gültig. Ein SyntaxError wird ausgelöst, wenn es in einem anderen Kontext verwendet wird.
Objekte, die __cocall__ implementieren, sollen ein Objekt zurückgeben, das dem Iterator-Protokoll gehorcht. Cofunktionen reagieren auf __cocall__ genauso wie gewöhnliche Generatorfunktionen auf __call__, d. h. durch Rückgabe eines Generator-Iterators.
Bestimmte Objekte, die andere aufrufbare Objekte umschließen, insbesondere gebundene Methoden, erhalten __cocall__-Implementierungen, die an das zugrunde liegende Objekt delegieren.
Neue Builtins, Attribute und C API-Funktionen
Um die Schnittstelle von Cofunktionen mit Nicht-Coroutinen-Code zu erleichtern, wird eine eingebaute Funktion costart bereitgestellt, deren Definition äquivalent ist zu:
def costart(obj, *args, **kwds):
return obj.__cocall__(*args, **kwds)
Es wird auch eine entsprechende C API-Funktion geben:
PyObject *PyObject_CoCall(PyObject *obj, PyObject *args, PyObject *kwds)
Es ist vorerst nicht spezifiziert, ob eine Cofunktion ein eigener Objekttyp ist oder, wie eine Generatorfunktion, einfach eine speziell markierte Funktionsinstanz. Im letzteren Fall sollte ein schreibgeschütztes boolesches Attribut __iscofunction__ bereitgestellt werden, um zu testen, ob ein gegebenes Funktionsobjekt eine Cofunktion ist.
Motivation und Begründung
Die Syntax yield from ist bei der Delegation eines Teils der Arbeit eines Generators an eine andere Funktion einigermaßen selbsterklärend. Sie kann auch effektiv bei der Implementierung von generatorbasierten Coroutinen verwendet werden, liest sich aber für diesen Zweck etwas umständlich und neigt dazu, die eigentliche Absicht des Codes zu verdecken.
Darüber hinaus ist die Verwendung von Generatoren als Coroutinen etwas fehleranfällig. Wenn man vergisst, yield from zu verwenden, wenn es hätte verwendet werden sollen, oder es verwendet, wenn es nicht hätte verwendet werden sollen, können die resultierenden Symptome obskur und verwirrend sein.
Schließlich besteht manchmal die Notwendigkeit, dass eine Funktion eine Coroutine ist, auch wenn sie nichts liefert. In diesen Fällen ist es notwendig, auf Tricks wie if 0: yield zurückzugreifen, um sie zu zwingen, ein Generator zu sein.
Die Konstrukte codef und cocall adressieren das erste Problem, indem die Syntax die Absicht direkt widerspiegelt, d. h. dass die Funktion Teil einer Coroutine ist.
Das zweite Problem wird dadurch gelöst, dass es unmöglich ist, Coroutinen- und Nicht-Coroutinen-Code auf eine Weise zu mischen, die keinen Sinn ergibt. Wenn die Regeln verletzt werden, wird eine Ausnahme ausgelöst, die genau angibt, was und wo das Problem liegt.
Zuletzt wird die Notwendigkeit von Dummy-Yields beseitigt, indem die Form der Definition bestimmt, ob die Funktion eine Coroutine ist, anstatt was sie enthält.
Prototyp-Implementierung
Eine Implementierung in Form von Patches für Python 3.1.2 finden Sie hier:
http://www.cosc.canterbury.ac.nz/greg.ewing/python/generators/cofunctions.html
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-3152.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT