这篇文章要解决的问题:How to Pass Value to Generators Using the “yield” Expression in Python
ref:https://python.plainenglish.io/yield-python-part-ii-e93abb619a16
1.如何传值
yield 是一个表达式!!!!
yield is an expression! It is used just like an expression would:
received = yield ‘hello’
In this case value of received is hello .
received = yield
Here, the value of received is None .
However, it’s been suggested to use the expression form sparingly also because of confusion.
但是也有人建议少用,因为容易引起混淆!
2.yield 生成器的几种状态
···python
from inspect import getgeneratorstate
def gen_echo():
while True:
received = yield
print(f'Inside method: {getgeneratorstate(echo)}')
print(f'You said: {received}')
echo = gen_echo()
print(f'After generator creation: {getgeneratorstate(echo)}')
print(f'First call value to generator: {next(echo)}')
print(f'After first call to generator: {getgeneratorstate(echo)}')
# sending value to generator
echo.send('hello')
print(f'After sending the value: {getgeneratorstate(echo)}')
···
C:\Users\HP\.conda\envs\torch1.8\python.exe D:/code/python_project/01-coroutine-py-mooc/8/demo_ccc.py
After generator creation: GEN_CREATED
First call value to generator: None
After first call to generator: GEN_SUSPENDED
Inside method: GEN_RUNNING
You said: hello
After sending the value: GEN_SUSPENDED
3.原理图
其实就是线程【用户级线程=也叫协程】的状态转换图!!!
3.协程练习
3.1 原始方式
def running_averager():
total = 0
count = 0
running_average = None
while True:
value = yield running_average
total += value
count += 1
running_average = total/count
averager = running_averager() # generator creation
next(averager) # priming
print(averager.send(10))
print(averager.send(20))
print(averager.send(30))
3.2 闭包【装饰器】方式
3.1相同的功能代码再用闭包的方式实现一遍,After priming, the generator is on suspend state, after which we can send data to a generator and get running_average.
Since we have to do that extra step of next() to generator, why not have it automated. We have a decorator to do that.
def prime(generator_fun):
'''
Method to prime generator function
'''
generator = generator_fun()
next(generator)
return generator
def running_averager():
'''
calculates average of values sent
'''
total = 0
count = 0
running_average = None
while True:
value = yield running_average
total += value
count += 1
running_average = total/count
iterable = [10, 11, 12, 13, 14, 15]
averager = prime(running_averager) # decorating
for value in iterable:
running_average = averager.send(value)
print(running_average)
输出:
10.0
10.5
11.0
11.5
12.0
12.5
4.总结
In summary, yield is an expression too and we can send value to a generator when it is in suspend state. The first suspend state is achieved by priming the generator.