4
votes

PEP-380 introduces the yield from syntax and says:

yield from <expr>

where is an expression evaluating to an iterable, from which an iterator is extracted. So the following are legal and make sense:

  1. yield from generators
  2. yield from generator_based_coroutine ( that use the @asyncio.coroutine decorator)

since both generators and generator based coroutines are instances of Iterable. However, I fail to understand why

yield from native_coroutines (using async/await syntax)

is legal? Since PEP-492 states that native coroutines don't implement the __iter__ and __next__ methods and therefore aren't iterable. However, there's no PEP that talks about this change in behavior of yield from to accept coroutine objects that are returned by native coroutines?

I know generator based coroutines will get deprecated in 3.10 but I still want to know why yield from works with native coroutines.

1

1 Answers

1
votes

However, I fail to understand why yield from native_coroutines (using async/await syntax) is legal? Since PEP-492 states that native coroutines don't implement the __iter__ and __next__ methods and therefore aren't iterable.

However, PEP 492 also states that "generator-based coroutines [...] can yield from native coroutine objects."

However, I fail to understand why yield from native_coroutines is legal?

Because otherwise native coroutines would not be usable from legacy code that used generator-based coroutines and yield from.

For example, at some point after async def was introduced, most asyncio primitives, including asyncio.sleep, were converted to async def coroutines. If those didn't support yield from, the conversion would break all existing asyncio code that awaited asyncio.sleep using yield from, previously the only possible way to await. Such backward incompatibility would have been a show-stopper for introduction of native coroutines, so it was avoided.