Coroutine, yield from, async await

#Use generator to implement coroutine

Why is the generator? Because the generator is similar to the pause feature. Yield

Look at a simple generator first.

def func():
    yield 1
    yield 2
    yield 3
    return "TT"
if __name__ == "__main__":
    gen = func()
    print(next(gen))
    print(next(gen))
    print(next(gen))
    print(next(gen))
"""
1
2
3
 Report an error
StopIteration: TT
"""

Generator generated and received values

"""
Builder   
 Not only can the output value
 Can also receive values
"""

def func():
    # 1. Can output value
    # 2. Can receive the value, the caller passes the incoming value
    html = yield "http://www.baidu.com"
    print(html)
    yield 2
    yield 3
    return "TT"
if __name__ == "__main__":
    #  Generator In addition to next, there is send
    gen = func()

    url = next(gen)
    # If it is send, an exception will be thrown
    # can gen.send(None)
    # Before starting send non-None, you must start the generator first.
    # 1。send(None) 2.next()

    html = "boby"
    a = gen.send(html)
    print(a)
    # send method can pass values ​​to the inside of the generator
    # Also you can restart the generator, execute to the next yield position, the same next method

yield from

# python3.3New features yield from

# Learn a chain before you learn
from itertools import chain
"""
 Chain can splicing multiple iterable objects into one, completing the for loop
"""
a = [1,2,3,4]
b = ["aa","bb","cc"]
c = {"key11":"111","key22":"222"}
for i in chain(a,b,c,range(10,13)):
    print(i)

# Next, we implement a chain ourselves
def my_chain(*args,**kwargs):
    for my_interable in args:
        for value in my_interable:
            yield value

for i in my_chain(a,b,c,range(10,13)):
    print(i)
    
#===================================================================    
# yield from iterable followed by an iterable object  
def my_chain(*args,**kwargs):
    for my_interable in args:
        yield from my_interable
"""
def my_chain(*args,**kwargs):
    for my_interable in args:
        yield from my_interable

for i in my_chain(a,b,c,range(10,13)):
    print(i)
    

"""
#=================================================================== 

def g1(gen):
    yield from gen

def main():
    g = g1()
    g.send(None)
"""
 Main caller
 G1 is the delegate generator
 Gen is a child generator

 Yield from creates a bidirectional channel between the caller and the child generator
 The value of the child generator yield is directly passed to the main
 The value sent by main is sent directly to gen, the child generator, not g=g1()
"""

Yield from example

final_result = {}

def sales_sum(pro_name):
    total = 0
    nums = []
    while True:
        x = yield
        print(pro_name+"Sales:", x)
        if not x:
            break
        total += x
        nums.append(x)
    return total, nums

def middle(key):
    while True:
        final_result[key] = yield from sales_sum(key)
        print(key+"The sales statistics are completed!!.")

def main():
    data_sets = {
        "bobby mask": [1200, 1500, 3000],
        "bobby mobile phone": [28,55,98,108 ],
        "bobby coat": [280,560,778,70],
    }
    for key, data_set in data_sets.items():
        print("start key:", key)
        m = middle(key)
        m.send(None) #  middle coroutine
        for value in data_set:
            m.send(value)   # Pass the value of each group to the coroutine
        m.send(None)
    print("final_result:", final_result)

if __name__ == '__main__':
    main()

"""
 If you don't use the above method, you need to handle the exception yourself.
"""
def sales_sum(pro_name):
    total = 0
    nums = []
    while True:
        x = yield
        print(pro_name+"Sales:", x)
        if not x:
            break
        total += x
        nums.append(x)
    return total, nums

if __name__ == "__main__":
    my_gen = sales_sum("bobby mobile phone")
    my_gen.send(None)
    my_gen.send(1200)
    my_gen.send(1500)
    my_gen.send(3000)
    try:
        my_gen.send(None)
    except StopIteration as e:
        result = e.value
        print(result)

Yield from running logic

"""
 copy 
"""

#pep380

#1. RESULT = yield from EXPR can be simplified to the following
# EXPR is an expression
# some instructions
"""
 _i: child generator, also an iterator
 _y: the value produced by the child generator
 _r:yield from the final value of the expression
 _s: the value sent by the caller via send()
 _e: exception object

"""

_i = iter(EXPR)      # EXPR is an iterable object, _i is actually a child generator;
try:
    _y = next(_i)   # Pre-exciton generator, the first value of the output is stored in _y;
except StopIteration as _e:
    _r = _e.value   # If the `StopIteration` exception is thrown, then the `value` attribute of the exception object is saved to _r, which is the return value of the simplest case;
else:
    while 1:    # Try to execute this loop, the delegate generator will block;
        _s = yield _y   # Produce the value of the child generator, wait for the caller `send()` value, and the value sent will be saved in _s;
        try:
            _y = _i.send(_s)    # _s, and try to execute downwards;
        except StopIteration as _e:
            _r = _e.value       # If the child generator throws an exception, then get the `value` attribute of the exception object to _r, exit the loop, and resume the running of the delegate generator;
            break
RESULT = _r     # _r is the value returned by the entire yield from expression.

"""
 1. The child generator may be just an iterator, not a generator that is a coroutine, so it does not support the .throw() and .close() methods;
 2. If the child generator supports the .throw() and .close() methods, but inside the child generator, both methods will throw an exception;
 3. The caller causes the child generator to throw an exception itself
 4. When the caller uses next() or .send(None), the next() function is called on the child generator. When the caller uses .send() to send a non-None value, the child generator is called. .send() method;
"""
_i = iter(EXPR)
try:
    _y = next(_i)
except StopIteration as _e:
    _r = _e.value
else:
    while 1:
        try:
            _s = yield _y
        except GeneratorExit as _e:
            try:
                _m = _i.close
            except AttributeError:
                pass
            else:
                _m()
            raise _e
        except BaseException as _e:
            _x = sys.exc_info()
            try:
                _m = _i.throw
            except AttributeError:
                raise _e
            else:
                try:
                    _y = _m(*_x)
                except StopIteration as _e:
                    _r = _e.value
                    break
        else:
            try:
                if _s is None:
                    _y = next(_i)
                else:
                    _y = _i.send(_s)
            except StopIteration as _e:
                _r = _e.value
                break
RESULT = _r

"""
 After reading the code, let's summarize the key points:

 1. The value produced by the child generator is directly passed to the caller; the value sent by the caller via .send() is passed directly to the child generator; if the send is None, the child generator is called. The __next__() method, if not None, calls the .send() method of the child generator;
 2. When the child generator exits, the last return EXPR will trigger a StopIteration (EXPR) exception;
 3. The value of the yield from expression is the first argument passed to the StopIteration exception when the child generator terminates;
 4. If the StopIteration exception occurs during the call, the delegate generator will resume running, and other exceptions will "bubble up";
 5. In the exception passed to the delegate generator, except for GeneratorExit, all other exceptions are passed to the child generator's .throw() method; if the StopIteration exception occurs when .throw() is called, then the delegate is restored. The generator is running, all other exceptions are "bubbling up";
 6. If you call .close() on the delegate generator or pass in a GeneratorExit exception, the sub-builder's .close() method is called, and if it is not, it is not called. If an exception is thrown when calling .close(), then "bubble" up, otherwise the delegate generator will throw a GeneratorExit exception.

"""

Async and await

# python 3.5 Previously, using the generator to complete the coroutine task
After #3.5, in order to make the semantics clearer, the async and await keywords were added to define the native coroutine.

async def dwonloader(url):
    return "1111"

async def download_url(url):
    # from 
    html = await dwonloader(url) #Awaitableobject
    return html

if __name__ == "__main__":
    coro = download_url("https://www.baidu.com")
    try:
        coro.send(None)
    except StopIteration as e:
        result = e.value
        print(result)

Intelligent Recommendation

Generator yield migrate await / async

Generator yield migrate await / async es6 using asynchronous await and async, old code uses a generator and yield, migration need to use the function to co.wrap Reference documents:https://github.com/...

Usage of async, await, yield, * in javascript

Usage of async and await Results of the Personal understanding of async means that this function is asynchronous. The keyword await is blocking (suspend the function and wait for the return result). I...

A nice async / await, generator / yield

async/await async function is a function of the async keyword declared. async AsyncFunction function is an example of the constructor, and which allows await keyword. async and await keywords so that ...

Coroutine keyword yield and yield from

yield When the yield keyword appears in a function, then this function is a generator. You can iterate with a for loop or a next() function. Yield can receive variables passed in from the outside worl...

Python coroutine--yield and yield from

yield and yield from The dictionary gives two definitions for the verb "to yield": yield and concession. For yield in Python generators, both meanings are true. The yield item line of code w...

More Recommendation

Python coroutine yield from

The difference between generator and coroutine The usage of yield in Python is very similar to return, both of which provide a return value, but the biggest difference between yield and return is that...

[-Flutter / dart syntax -】 Sync * and Async *, Yield and Yield *, Async and Await

Foreword category Keyword Return type partner Multi-element synchronization sync* Iterable<T> yield、yield* Single element async Future<T> await Multi-element asynchronous async* Stream<...

Async await implementation principle generator + yield + promise

Generator function The Generator function is a state machine. How many states are there, how many states there are. When the Generator function is executed, it actually returns a pointer object (the i...

[Translation] JavaScript - Generator-Yield/Next and Async-Await

Original address:Javascript - Generator-Yield/Next & Async-Await Original author:Deepak Gupta The translation comes from:Nuggets translation plan This article is permanently linked:github.com/xitu...

Generators / yield (es2015) and Async / await (es7) difference

Generators / yield (es2015) and Async / await (es7)...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top