I'm trying to learn more about coroutines, and the event loop in asyncio.
To my knowledge, a coroutine is a generator function. You can define a coroutine with async def. All the things that you can do to a generator functon, you can do to a coroutine. You can do coroutine.send(None), coroutine.throw(Exception), coroutine.close(). Now I have 2 questions about coroutines :
- When you add - yieldto a function it become a generator functon. This means that you have to include yield in every generator at least once. With most coroutines (like in discord.py) I do not see the yield key word in it at all! So how are they generators? Maybe the- awaitkeyword does yielding or something? Please explain.
- If generators and coroutines are the same, why do they have different names? 
Now I think I know a little bit about generator functions, they yield, you can send them stuff and even exceptions. And coroutines are the same I think.
So, I know this: the event loop stops a coroutine when it sees the await keyword (this keyword just calls .__await__() method). And then it just executes the function after that keyword then moves on to a different task. Simple enough.
But i do not understand how this gives back control to the event loop.
Perhaps the event loop does this when running a task : coroutine.send(None) so it waits till a yield to context switch? So maybe the await is a yield? But if it does yield, that would make it a generator method and the actual coroutine is not yielding but the __await__() is?
Very confusing stuff. Could someone explain what await does and what the method .__await__() does?
So to wrap my questions up:
- What is the difference between a Generator functon and a Co-routine?
- What are the different use cases between those two?
- How do they work differently?
- How does asyncio run co-routines until the await?
- What does __await__()method do?
- Why don't I see any yields in co-routines?
