python3 yield from skills up

#python#coroutine
at

python3 yield from skills up

The explanation that yield from g is equivalent to for v in g: yield v does not even begin to do justice to what yield from is all about. Because, let's face it, if all yield from does is expand the for loop, then it does not warrant adding yield from to the language and preclude a whole bunch of new features from being implemented in Python 2.x. Think of yield from as providing a transparent two-way channel from the caller to the sub-generator.

sending data to a generator using yield from

def generator():
    """
    A generator(coroutine) that writes data *sent* to it to fd, socket, etc.
    """
    while True:
        w = (yield)
        print('>> %s' % w)


def gen_wrapper(c):          # c for coroutine
    yield from c

if __name__ == '__main__':
    gen = generator()
    wrap = gen_wrapper(gen)
    wrap.send(None)  # initialize the coroutine
    for i in range(4):
        gen.send(i)

exception handling for yield from

class TransactionException(Exception):
    pass


def generator():
    while True:
        try:
            w = (yield)
        except TransactionException:
            print('******')
        else:
            print('>> ', w)


def gen_wrapper(c):          # c for coroutine
    yield from c


if __name__ == '__main__':
    gen = generator()
    wrap = gen_wrapper(gen)
    wrap.send(None)
    for i in [0, 1, 2, 3, 'exc', 4]:
        if i == 'exc':
            wrap.throw(TransactionException)
        else:
            wrap.send(i)

close outside of block

def generator():
    while True:
        w = (yield)
        print('>> ', w)


def gen_wrapper(c):          # c for coroutine
    yield from c


if __name__ == '__main__':
    gen = generator()
    wrap = gen_wrapper(gen)
    wrap.send(None)
    for i in [0, 1, 2, 3, 'close', 4]:
        if i == 'close':
            wrap.close()
        else:
            wrap.send(i)

benefits of yield

  • Using a generalization of the StopIteration exception makes it easy for other kinds of iterators to participate in the protocol without having to grow an extra attribute or a close() method.
  • It simplifies the implementation, because the point at which the return value from the subgenerator becomes available is the same point at which the exception is raised. Delaying until any later time would require storing the return value somewhere.
  • the primary benefits of yield from come when you've written a generator that uses these techniques and when it needs to be refactored.

and especially this part: https://www.python.org/dev/peps/pep-0380/#generators-as-threads

coroutine is not a callback (which is yield is not a function)

The difference is that whenever the generator "yields" a value the execution of the generator is paused and the code continues where the generator was called.

reference

http://legacy.python.org/dev/peps/pep-0380/ http://legacy.python.org/dev/peps/pep-0342/ http://stackoverflows.com

« Link post