This post is about PEP-0380

A syntax is proposed for a generator to delegate part of its operations to another generator. This allows a section of code containing ‘yield’ to be factored out and placed in another generator. Additionally, the subgenerator is allowed to return with a value, and the value is made available to the delegating generator.

Basically, It’s a way to chain generators(generator is routine that yield to immediate caller. with yield from),And anthor iterator/generator can be used to return a value.

yield from <expr>

from PEP-0380

where is an expression evaluating to an iterable, from which an iterator is extracted. The iterator is run to exhaustion, during which time it yields and receives values directly to or from the caller of the generator containing the yield from expression (the “delegating generator”).

Furthermore, when the iterator is another generator, the subgenerator is allowed to execute a return statement with a value, and that value becomes the value of the yield from expression.

Here is useful example for “yield from” where I used yield from to do DFS over a tree. dfs_internal is generator that recursively calls itself and returning one child at a time.

    def __iter__(self):
        def dfs_internal(node):
            yield node
            for child in node.children:
                yield from dfs_internal(child)
        yield from dfs_internal(self.root)

Here is the yield from is described

The full semantics of the yield from expression can be described in terms of the generator protocol as follows:

Any values that the iterator yields are passed directly to the caller.

Any values sent to the delegating generator using send() are passed directly to the iterator. If the sent value is None, the iterator’s next() method is called. If the sent value is not None, the iterator’s send() method is called. If the call raises StopIteration, the delegating generator is resumed. Any other exception is propagated to the delegating generator.

Exceptions other than GeneratorExit thrown into the delegating generator are passed to the throw() method of the iterator. If the call raises StopIteration, the delegating generator is resumed. Any other exception is propagated to the delegating generator.

If a GeneratorExit exception is thrown into the delegating generator, or the close() method of the delegating generator is called, then the close() method of the iterator is called if it has one. If this call results in an exception, it is propagated to the delegating generator. Otherwise, GeneratorExit is raised in the delegating generator.

The value of the yield from expression is the first argument to the StopIteration exception raised by the iterator when it terminates.

return expr in a generator causes StopIteration(expr) to be raised upon exit from the generator.