- generators found in Python 3.3
- event loop in the form of asyncio: In Python 3.4, theasyncio.coroutinedecorator was used to label a function as acting as a coroutine that was meant for use withasyncioand its event loop.
- yield fromto- awaitin Python 3.5
A Python generator is any function containing one or more yield expressions:
def func():            # a function
    return
def genfunc():         # a generator function
    yieldWe propose to use the same approach to define asynchronous generators:
async def coro():      # a coroutine function
    await smth()
async def asyncgen():  # an asynchronous generator function
    await smth()
    yield 42The result of calling an asynchronous generator function is an asynchronous generator object, which implements the asynchronous iteration protocol defined in PEP 492.
It is a SyntaxError to have a non-empty return statement in an asynchronous generator.
- Generations: yield,yield from
- Awaitable: used for await expression.
- Future-like object: An object with an __await__method
- Coroutine object
- Generator-based coroutines (function): @types.coroutine+yield
- Native coroutines (function): async def+await+return value
 
- Generator-based coroutines (function): 
 
- Future-like object: An object with an 
- Asynchronous context manager: An asynchronous context manager has __aenter__and__aexit__methods and can be used withasync with.
- Asynchronous iterable: An object with an __aiter__method, which must return an asynchronous iterator object. Can be used withasync for.- Asynchronous iterator: An asynchronous iterator has an __anext__method
 
- Asynchronous iterator: An asynchronous iterator has an 
Key properties of coroutines:
- async deffunctions are always coroutines, even if they do not contain- awaitexpressions.
- It is a SyntaxErrorto haveyieldoryield fromexpressions in an async function.
async def read_data(db):
    data = await db.fetch('SELECT ...')
    ...await, similarly to yield from, suspends execution of read_data coroutine until db.fetch awaitable completes and returns the result data.
It uses the yield from implementation with an extra step of validating its argument.
await only accepts an awaitable, which can be one of:
- A native coroutine object returned from a native coroutine function.
- A generator-based coroutine object returned from a function decorated with types.coroutine().
- An object with an __await__method returning aniterator.- Any yield fromchain of calls ends with ayield. This is a fundamental mechanism of howFuturesare implemented. Since, internally, coroutines are a special kind of generators, everyawaitis suspended by ayieldsomewhere down the chain ofawaitcalls
- To enable this behavior for coroutines, a new magic method called __await__is added. Inasyncio, for instance, to enableFutureobjects in await statements, the only change is to add__await__ = __iter__line toasyncio.Futureclass.
- Objects with __await__method are calledFuture-likeobjects in the rest of this PEP.
- It is a TypeErrorif__await__returns anything but an iterator.
 
- Any 
Exceptions
- It is a SyntaxErrorto useawaitoutside of anasync deffunction (like it is aSyntaxErrorto useyieldoutside ofdeffunction).
- It is a TypeErrorto pass anything other than anawaitable objectto anawaitexpression.
An asynchronous context manager is a context manager that is able to suspend execution in its enter and exit methods.
To make this possible, a new protocol for asynchronous context managers is proposed. Two new magic methods are added: __aenter__ and __aexit__. Both must return an awaitable.
Call asynchronous context manager using async with.
An asynchronous iterable is able to call asynchronous code in its iter implementation, and asynchronous iterator can call asynchronous code in its next method. To support asynchronous iteration:
- An object must implement an __aiter__method returning an asynchronous iterator object.
- An asynchronous iterator object must implement an __anext__method returning an awaitable.
- To stop iteration __anext__must raise aStopAsyncIterationexception.
async for TARGET in ITER:
    BLOCK
else:
    BLOCK2