The chapter on Generators was very interesting and helpful. Thank you. There are a few concepts used in the chapter that are not explained or at least not explained well that I believe should or could be.
One such concept is the coroutine. The chapter includes a function entitled coroutine. I think I understand what that particular function does: it takes an input generator function and essentially primes it for use by "next"ing it once to pause it at the first yield so that it is "ready to go", and then returns the generator object for use by the calling code. However, I don't understand what general computing approach this exemplifies. Of course, this book should not be a textbook on general computer science concepts. However, even a simple sentence or two here of explanation would have helped me immensely.
A similar issue is, I believe, relevant with respect to the "push"ing and "pull"ing discussed in the tokenization examples. The two different examples in the book show how a string can be tokenized into words using generators. I fought my way through these two examples and believe I understand what is happening on a line-by-line basis. However, I don't understand how one example demonstrates "finishing via pulling" and the other "start[ing] via pushing". Again, I don't think the book needs an in-depth explanation of these concepts, but it would benefit from giving even a sentence or two of clarification...what is being pushed/pulled, where does that happen in the code, how do these represent general approaches to using generators, etc.
Thanks for considering these suggestions from someone who has read enough badly written computer programming books to very much appreciate not only your expertise but also your ability to clearly explain difficult concepts.