2010-08-10 20:25:26 -04:00
|
|
|
|
PEP: 3152
|
|
|
|
|
Title: Cofunctions
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Gregory Ewing <greg.ewing@canterbury.ac.nz>
|
2015-04-19 03:52:35 -04:00
|
|
|
|
Status: Draft
|
2010-08-10 20:25:26 -04:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 13-Feb-2009
|
|
|
|
|
Python-Version: 3.3
|
|
|
|
|
Post-History:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
A syntax is proposed for defining and calling a special type of
|
|
|
|
|
generator called a 'cofunction'. It is designed to provide a
|
|
|
|
|
streamlined way of writing generator-based coroutines, and allow the
|
|
|
|
|
early detection of certain kinds of error that are easily made when
|
|
|
|
|
writing such code, which otherwise tend to cause hard-to-diagnose
|
|
|
|
|
symptoms.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
This proposal builds on the 'yield from' mechanism described in PEP
|
|
|
|
|
380, and describes some of the semantics of cofunctions in terms of
|
|
|
|
|
it. However, it would be possible to define and implement cofunctions
|
|
|
|
|
independently of PEP 380 if so desired.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
Cofunction definitions
|
|
|
|
|
----------------------
|
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
A new keyword ``codef`` is introduced which is used in place of
|
|
|
|
|
``def`` to define a cofunction. A cofunction is a special kind of
|
|
|
|
|
generator having the following characteristics:
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
1. A cofunction is always a generator, even if it does not contain any
|
2010-08-10 20:25:26 -04:00
|
|
|
|
``yield`` or ``yield from`` expressions.
|
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
2. A cofunction cannot be called the same way as an ordinary function.
|
|
|
|
|
An exception is raised if an ordinary call to a cofunction is
|
|
|
|
|
attempted.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
Cocalls
|
|
|
|
|
-------
|
|
|
|
|
|
|
|
|
|
Calls from one cofunction to another are made by marking the call with
|
2011-10-30 07:46:47 -04:00
|
|
|
|
a new keyword ``cocall``. The expression ::
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
cocall f(*args, **kwds)
|
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
is semantically equivalent to ::
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
yield from f.__cocall__(*args, **kwds)
|
|
|
|
|
|
|
|
|
|
except that the object returned by __cocall__ is expected to be an
|
|
|
|
|
iterator, so the step of calling iter() on it is skipped.
|
|
|
|
|
|
|
|
|
|
The full syntax of a cocall expression is described by the following
|
2011-10-30 07:46:47 -04:00
|
|
|
|
grammar lines::
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
atom: cocall | <existing alternatives for atom>
|
|
|
|
|
cocall: 'cocall' atom cotrailer* '(' [arglist] ')'
|
|
|
|
|
cotrailer: '[' subscriptlist ']' | '.' NAME
|
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
The ``cocall`` keyword is syntactically valid only inside a
|
|
|
|
|
cofunction. A SyntaxError will result if it is used in any other
|
|
|
|
|
context.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
Objects which implement __cocall__ are expected to return an object
|
2011-10-30 07:46:47 -04:00
|
|
|
|
obeying the iterator protocol. Cofunctions respond to __cocall__ the
|
2010-08-10 20:25:26 -04:00
|
|
|
|
same way as ordinary generator functions respond to __call__, i.e. by
|
|
|
|
|
returning a generator-iterator.
|
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
Certain objects that wrap other callable objects, notably bound
|
|
|
|
|
methods, will be given __cocall__ implementations that delegate to the
|
|
|
|
|
underlying object.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
New builtins, attributes and C API functions
|
|
|
|
|
--------------------------------------------
|
|
|
|
|
|
|
|
|
|
To facilitate interfacing cofunctions with non-coroutine code, there will
|
2011-10-30 07:46:47 -04:00
|
|
|
|
be a built-in function ``costart`` whose definition is equivalent to ::
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
def costart(obj, *args, **kwds):
|
|
|
|
|
return obj.__cocall__(*args, **kwds)
|
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
There will also be a corresponding C API function ::
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
PyObject *PyObject_CoCall(PyObject *obj, PyObject *args, PyObject *kwds)
|
|
|
|
|
|
|
|
|
|
It is left unspecified for now whether a cofunction is a distinct type
|
|
|
|
|
of object or, like a generator function, is simply a specially-marked
|
2011-10-30 07:46:47 -04:00
|
|
|
|
function instance. If the latter, a read-only boolean attribute
|
|
|
|
|
``__iscofunction__`` should be provided to allow testing whether a
|
|
|
|
|
given function object is a cofunction.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Motivation and Rationale
|
|
|
|
|
========================
|
|
|
|
|
|
|
|
|
|
The ``yield from`` syntax is reasonably self-explanatory when used for
|
|
|
|
|
the purpose of delegating part of the work of a generator to another
|
2011-10-30 07:46:47 -04:00
|
|
|
|
function. It can also be used to good effect in the implementation of
|
2010-08-10 20:25:26 -04:00
|
|
|
|
generator-based coroutines, but it reads somewhat awkwardly when used
|
|
|
|
|
for that purpose, and tends to obscure the true intent of the code.
|
|
|
|
|
|
|
|
|
|
Furthermore, using generators as coroutines is somewhat error-prone.
|
2011-10-30 07:46:47 -04:00
|
|
|
|
If one forgets to use ``yield from`` when it should have been used, or
|
|
|
|
|
uses it when it shouldn't have, the symptoms that result can be
|
2010-08-10 20:25:26 -04:00
|
|
|
|
obscure and confusing.
|
|
|
|
|
|
|
|
|
|
Finally, sometimes there is a need for a function to be a coroutine
|
|
|
|
|
even though it does not yield anything, and in these cases it is
|
2011-10-30 07:46:47 -04:00
|
|
|
|
necessary to resort to kludges such as ``if 0: yield`` to force it to
|
|
|
|
|
be a generator.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
The ``codef`` and ``cocall`` constructs address the first issue by
|
|
|
|
|
making the syntax directly reflect the intent, that is, that the
|
|
|
|
|
function forms part of a coroutine.
|
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
The second issue is addressed by making it impossible to mix coroutine
|
|
|
|
|
and non-coroutine code in ways that don't make sense. If the rules
|
|
|
|
|
are violated, an exception is raised that points out exactly what and
|
|
|
|
|
where the problem is.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
2011-10-30 07:46:47 -04:00
|
|
|
|
Lastly, the need for dummy yields is eliminated by making the form of
|
|
|
|
|
definition determine whether the function is a coroutine, rather than
|
|
|
|
|
what it contains.
|
2010-08-10 20:25:26 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Prototype Implementation
|
|
|
|
|
========================
|
|
|
|
|
|
|
|
|
|
An implementation in the form of patches to Python 3.1.2 can be found
|
|
|
|
|
here:
|
|
|
|
|
|
|
|
|
|
http://www.cosc.canterbury.ac.nz/greg.ewing/python/generators/cofunctions.html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|