Like the articles? Buy the book! Dead Simple Python by Jason C. McDonald is available from No Starch Press.
Programming is often about waiting....
For further actions, you may consider blocking this person and/or reporting abuse
Very in-depth article about generators! I enjoyed it a lot.
At first your use of the term "coroutine" when referring to generators that use
.send()
andyield from
was a bit jarring to me — as of Python 3.6 a coroutine is the return value of a coroutine function:But then I realized that you were probably using that term as the more general computer science concept of a routine that can be paused during execution (see Coroutine).
Still, the fact that
coroutine
is now "reserved terminology" in Python might be confusing to some people. Perhaps a disclaimer that coroutine refers more to the computer science general concept rather than thecoroutine
built-in type would be helpful. :-)Well, no, not precisely. In Python, the term "coroutine" does indeed officially refer to both. In fact, the two have their own qualified names.
What I described is called a simple coroutine, which was defined in PEP 342, and further expanded in PEP 380. Coroutines first appeared in Python 2.5, and continue to be a distinct and fully supported language feature.
You're referring to a native coroutine (also called an asynchronous coroutine), which was defined in PEP 492, and was based on simple coroutines, but designed to overcome some specific limitations of the former. Native coroutines first appeared in Python 3.5. Again, this didn't replace simple coroutines, but rather offered another form of them specifically for use in concurrency.
I'll put a little clause or two about this in the article.
Also, don't worry, I'll be coming back around to async and concurrency soon; once that's written, I'll come back to this article and link across.
Thanks for clarifying :) Actually, I wasn’t aware that native coroutine was the official name for generators used in this fashion.
Thanks! Just to be clear, I was simply raising the concern that as async programming is becoming more and more used/popular in Python and most people talk about coroutines as a shorthand for async coroutines, using the shorthand to refer to native ones could be confusing. Anyway I think you’ve got the point so thanks for taking that into account. :)
Uh oh! I just realized I'd had a dyslexic moment, and read something in PEP 492 backwards...
What I described are simple coroutines, and the newer type is the native coroutine (also called an "asyncronous coroutine").
Blinks
Anyhow, I've gone back and edited both my comment and article. Thanks again...if you hadn't asked about that, I would have never caught my error!
Great article Jason!
Just a couple of details:
An exception can be raised at the current yield with foo.raise().
->with foo.throw().
In
sorted(self.letters.items(), key=lambda kv: kv[1])
the lambda can be replaced with operator.itemgetter(1), it's one of my favorite small things that are in the standard library :DI was wondering if there was a way to simplify the coroutine code, using a context manager. The
__enter__
could callsend(None)
and the__exit__
could callclose()
.With a simple generator is easy to do something similar:
But the same doesn't work for a coroutine...
As a first I came up with this:
I came up with something like this then:
but I'm not sure it's improving much :D
Ooh! Thanks for catching that typo! That would have been confusing.
As to the lambda or
itemgetter()
, I'd actually gone back and forth between the two in writing that example. I think using the lambda there is my own personal preference more than anything.That is certainly a clever combination of a context and a coroutine, by the way. (Naturally, I didn't discuss contexts in this article, as I haven't discussed them yet in the series.)
Thanks for the feedback.
The way it presented generators, i knew it would be a 👌 read, and i was right!
Taking the time to cover only those two helps a lot, best article on coroutines i've read to date. Rhanks for writing this up 👍