#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
"""
"""
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
# 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()
"""
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)
"""
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.
"""
# 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)
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 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...
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 ...
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...
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...
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...
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<...
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...
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)...