Generators versus Coroutines

T

Timothy Fitz

It seems to me that in python, generators are not truly coroutines. I
do not understand why. What I see is that generators are used almost
exclusively for generation of lists just-in-time. Side effects are
frowned upon. Coroutines, in contrast, are like split functions where
side effects are often as important or more important than return
values. I am currently writing a real time strategy game where I have
visual effects and use generators as coroutines which yield after
processing a single frame of the effect. I can easily make an object
rotate indefinitely with a scant four or five lines of code, all of
which is in one place. So knowing that the difference between a
generator and a coroutine is minor, I come (in a very roundabout way)
to my issue. Why can I use "return" without an expression and it
implicitly returns None but I can't do the same thing with "yield" ?
 
T

Tim Peters

[Timothy Fitz]
It seems to me that in python, generators are not truly coroutines.

Yes, formally speaking Python generators are semi-coroutines.
I do not understand why.

Please read the PEP:

http://www.python.org/peps/pep-0255.html
What I see is that generators are used almost exclusively for
generation of lists just-in-time. Side effects are frowned upon.

Simple uses are naturally most common.
Coroutines, in contrast, are like split functions where
side effects are often as important or more important than return
values. I am currently writing a real time strategy game where I have
visual effects and use generators as coroutines which yield after
processing a single frame of the effect. I can easily make an object
rotate indefinitely with a scant four or five lines of code, all of
which is in one place. So knowing that the difference between a
generator and a coroutine is minor, I come (in a very roundabout way)
to my issue. Why can I use "return" without an expression and it
implicitly returns None

If you explicitly intend to return None as a value, it's terrible
practice to spell that as

return

instead of as

return None

It's equally terrible practice to rely on that "falling off the end"
of a Python function returns None, when you expliclty intend to return
a None value.

Plain "return" is intended to be used in Python only when
*conceptually* no value is being returned, as in "a subroutine" as
opposed to "a function". The language doesn't enforce the latter
distinction, but it's intended all the same.
but I can't do the same thing with "yield" ?

It's the purpose of "yield" to deliver a value. There was no intent
that it be possible to yield without delivering a value. If you want
to deliver the value None, then say

yield None

If you want a concept of yielding without delivering a value, that's
simply not a use case Python's generators intended to address. If you
wish, you can adhere to a *convention* that "yield None" (or "yield
False", or "yield 42", ...) means "I'm not really delivering a value".
 
T

Timothy Fitz

Tim Peters said:
If you explicitly intend to return None as a value, it's terrible
practice to spell that as

return

instead of as

return None

It's equally terrible practice to rely on that "falling off the end"
of a Python function returns None, when you expliclty intend to return
a None value.

It was not that I want to explicitly return None, I specifically don't
want to return anything, it's just that None happens to be the default
for return so it seems like a convention to adhere to.
If you want a concept of yielding without delivering a value, that's
simply not a use case Python's generators intended to address. If you
wish, you can adhere to a *convention* that "yield None" (or "yield
False", or "yield 42", ...) means "I'm not really delivering a value".

It's not a use case, but why not? And should it be? I know generators
are semi-coroutines, but the fact is that their useage outside of
value generation is just as useful and should be adressed as such. I
do not see how accepting a plain yield would break anything at all.

I have read the PEP, twice, and I don't see why it -wasn't- addressed.
Seems to me to be a fairly large arbitrary decision.
 
D

Dominic

values. I am currently writing a real time strategy game where I have
I have written a simple 2D-real-time vehicle simulator in Python
(+ graphics library Allegro), using chained generators
which works well enough.

If your game is more ambitious, spend some time designing
a good architecture and specify your components' interfaces.
Then you could generate your code-skeleton from that;
simple generators should be sufficient to implement
your methods which are then driven by your architectures
"execution model".

ciao,
Dominic
 
T

Tim Peters

[Tim Peters]
[Timothy Fitz]
It's not a use case, but why not?

In the years generators were discussed before they were implemented,
nobody asked for that.
And should it be?

Not by my lights, no.
I know generators are semi-coroutines, but the fact is that their
useage outside of value generation is just as useful and should be
adressed as such. I do not see how accepting a plain yield would
break anything at all.

The vast majority of generator applications (as you said
before,"generators are used almost exclusively for generation of lists
just-in-time", so you already know this) have no use for that; so, for
the vast majority of generator applications, allowing it anyway would
offer nothing of value, but would reduce the quality of compile-time
error-checking.
I have read the PEP, twice, and I don't see why it -wasn't- addressed.

If someone asked for a thing, it got into the PEP. Nobody wanted it.
Seems to me to be a fairly large arbitrary decision.

For general coroutines it would have been. For Simple Generators (the
PEP's title) I think it was the right decision -- "simple" isn't
consistent with piling on gimmicks.

If you want to change it, write a new PEP.
 
T

Timothy Fitz

Dominic said:
I have written a simple 2D-real-time vehicle simulator in Python
(+ graphics library Allegro), using chained generators
which works well enough.

If your game is more ambitious, spend some time designing
a good architecture and specify your components' interfaces.
Then you could generate your code-skeleton from that;
simple generators should be sufficient to implement
your methods which are then driven by your architectures
"execution model".

ciao,
Dominic

It really was never an issue of "Python can't handle this." it was
more of an issue of "Python should more openly support this." I am
championing generators because they make programming SO much easier in
cases, and people really just don't use them outside if list
generation, which saddens me.
 
T

Timothy Fitz

For general coroutines it would have been. For Simple Generators (the
PEP's title) I think it was the right decision -- "simple" isn't
consistent with piling on gimmicks.

If you want to change it, write a new PEP.

Hmm, I do agree in the context of "Simple Generators" yield implying
None would not make sense and (as shown by the fact that nobody else
seems to care) is a good parse-time error facility.

Is there, then, demand for full on Coroutines? I will live having to
type those extra four letters, or maybe I'll cop out and yield 0 (hah)
but it seems other people are used to coroutines in other languages
(python is my first and only) and there might be demand.

(Also, my first post on Usenet, ever, and in under two hours I get a
respond from someone whose name I recognize on sight... I am
impressed!)
 
P

Paul McGuire

Timothy Fitz said:
I have written a simple 2D-real-time vehicle simulator in Python
(+ graphics library Allegro), using chained generators
which works well enough.

If your game is more ambitious, spend some time designing
a good architecture and specify your components' interfaces.
Then you could generate your code-skeleton from that;
simple generators should be sufficient to implement
your methods which are then driven by your architectures
"execution model".

ciao,
Dominic

It really was never an issue of "Python can't handle this." it was
more of an issue of "Python should more openly support this." I am
championing generators because they make programming SO much easier in
cases, and people really just don't use them outside if list
generation, which saddens me.[/QUOTE]

Have you looked at SimPy? This is a discrete event simulation package in
pure Python, using generators in simulation objects to implement the
objects' behavior, while managing state, blocking on waits between objects,
etc. I think this may be more in the realm you are thinking, beyond simple
"list generation."

-- Paul
 
D

Dominic

> It really was never an issue of "Python can't handle this." it was
> more of an issue of "Python should more openly support this." I am
> championing generators because they make programming SO much easier in
> cases, and people really just don't use them outside if list
> generation, which saddens me.
Coroutines are much more powerful than Python's generators and
they can be easily abused to create unstructured
"goto"-like programs thus I assume it would still be a good idea
to put most effort into your architecture and it's
underlying execution model regardless of what you finally
use to keep state: coroutines, threads, (nested) generators.
Try to hide the implementation if you can.

Nesting generators works, but I have to admit
it's (probably) not very elegant.
I would also prefer coroutines for simulation and games as
a module similar to thread/threading.

I think Michael Jackson wrote a converter for COBOL
in the 70s, which would "invert" active entities into
ordinary functions keeping their state in ordinary data structures.
This can certainly be done in Python too.
Maybe this helps.


Ciao,
Dominic


P.S. Many programming languages do not even have
support for "generators", e.g. Java

Ha! Maybe @decorators are the solution ! ;-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top