[Python-ideas] Generator/Coroutiine Ontology (was async/await in Python)

Nick Coghlan ncoghlan at gmail.com
Sat Apr 25 06:02:24 CEST 2015

On 18 April 2015 at 16:05, Andrew Barnert
<abarnert at yahoo.com.dmarc.invalid> wrote:
> On Apr 17, 2015, at 21:48, Rustom Mody <rustompmody at gmail.com> wrote:
>> On Sat, Apr 18, 2015 at 12:28 AM, Yury Selivanov
>> <yselivanov.ml at gmail.com> wrote:
>>> Hello python-ideas,
>>> Here's my proposal to add async/await in Python.
>>> I believe that PEPs 380 and 3156 were a major breakthrough for Python 3,
>> I am also interested in this topic --- from the other side.
>> As a teacher of python it is my finding that the
>> terminology/documentation around generators is rather chaotic and
>> messy.
>> Basically given:
>> def foo():
>>  yield 1
>> bar = foo()
>> what do we call foo and what do we call bar?
>> It is suggested that foo is "generator-function" and bar is "generator-object"
>> Unfortunately python does not aid this distinction; witness
>>>>> def foo():
>> ...  yield 1
>> ...
>>>>> bar = foo()
>>>>> type(foo)
>> <class 'function'>
>>>>> type(bar)
>> <class 'generator'>
> I assume you're ok with the type(bar); the type of a generator object is named "generator", just like the type of a bound method object is named "method" and the type of an integer object is named "int", and so on.
> So presumably you don't like the former. But what about it?
> The only thing I can imagine is the fact that, even though a generator function is conceptually a "subkind" of function, there is no generator function subtype of the function type?
> But so what? There's no closure function subtype, just functions whose closure is nonempty; there's no positive int subtype, just ints whose value is positive; etc. And likewise, there's no callable supertype that function and method (and other things) inherit.
> If there were some additional API that a generator function should provide that other functions don't (or some implementation reason that makes it worth subclassing for convenience, I suppose), that would be a good reason for needing a subtype. For example, generator a subtype of iterator, just as file is, because they both add new methods that don't make sense for the base iterator type.
> But just wanting repr(type(x)) to give you more information about x, that's not a good reason to add a subtype.
> So, it seems to me like both of these are returning something you should reasonably expect.

Catching up on email following PyCon travel, there's a reasonable
question here related to the repr() of "foo" itself:

    >>> def foo():
    ...     yield 1
    >>> foo
    <function foo at 0x7f7dad9f7bf8>
    >>> import dis
    >>> dis.show_code(foo)
    Name:              foo
    Filename:          <stdin>
    Argument count:    0
    Kw-only arguments: 0
    Number of locals:  0
    Stack size:        1
     0: None
     1: 1

Modifying the repr of a function based on whether or not the GENERATOR
flag was set on the code object would be quite doable. For example,
the above could be:

    >>> foo
    <function foo at 0x7f7dad9f7bf8 (generator)>

type(foo) would still be unchanged, we'd just be exposing some
additional info in the value repr().

While it's a less significant behavioural difference than being a
generator function, a non-empty closure could conceivably also be
reported in the repr():

    <function foo at 0x7f7dad9f7bf8 (closure)>
    <function foo at 0x7f7dad9f7bf8 (closure,generator)>


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list