Initially (PEP 380), yield from syntax was introduced to be used for delegating to a "subgenerator." Later it was used with now deprecated generator-based coroutines.
I cannot find out what kind of objects yield from can be applied to in general. My first conjecture was that it only requires __iter__ method on the object to return an iterator. Indeed, the following works with Python 3.8:
class C:
def __init__(self, n):
self.n = n
def __iter__(self):
return iter(range(self.n))
def g(n):
yield from C(n)
print(tuple(g(3)))
However, it also works with some awaitables, like asyncio.sleep(1), which do not have __iter__ method.
What is the general rule? What determines if an object can be given as an argument to yield from form?
You can check how CPython evaluates that statement. From this follows it needs to be either a coroutine or an iterable: