使用generator和send()的一些用例
使用send()的生成器允许:
记住执行的内部状态
我们走到哪一步了
我们数据的当前状态是什么
返回值序列
接收输入序列
下面是一些用例:
观察尝试遵循食谱
让我们有一个配方,它期望以某种顺序预先定义一组输入。
我们可以:
create a watched_attempt instance from the recipe
let it get some inputs
with each input return information about what is currently in the pot
with each input check, that the input is the expected one (and fail if it is not)
def recipe():
pot = []
action = yield pot
assert action == ("add", "water")
pot.append(action[1])
action = yield pot
assert action == ("add", "salt")
pot.append(action[1])
action = yield pot
assert action == ("boil", "water")
action = yield pot
assert action == ("add", "pasta")
pot.append(action[1])
action = yield pot
assert action == ("decant", "water")
pot.remove("water")
action = yield pot
assert action == ("serve")
pot = []
yield pot
要使用它,首先创建watched_attempt实例:
>>> watched_attempt = recipe()
>>> watched_attempt.next()
[]
对.next()的调用是启动生成器执行所必需的。
返回值显示,我们的罐目前是空的。
现在按照食谱的要求做一些动作:
>>> watched_attempt.send(("add", "water"))
['water']
>>> watched_attempt.send(("add", "salt"))
['water', 'salt']
>>> watched_attempt.send(("boil", "water"))
['water', 'salt']
>>> watched_attempt.send(("add", "pasta"))
['water', 'salt', 'pasta']
>>> watched_attempt.send(("decant", "water"))
['salt', 'pasta']
>>> watched_attempt.send(("serve"))
[]
如我们所见,罐子终于空了。
万一,一个人不遵循配方,它会失败(什么可能是期望的结果观看
试着做点东西——刚知道我们在接到指示时没有足够注意。
>>> watched_attempt = running.recipe()
>>> watched_attempt.next()
[]
>>> watched_attempt.send(("add", "water"))
['water']
>>> watched_attempt.send(("add", "pasta"))
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-21-facdf014fe8e> in <module>()
----> 1 watched_attempt.send(("add", "pasta"))
/home/javl/sandbox/stack/send/running.py in recipe()
29
30 action = yield pot
---> 31 assert action == ("add", "salt")
32 pot.append(action[1])
33
AssertionError:
注意,:
预期的步骤有一个线性序列
步骤可能会有所不同(有些是移除,有些是添加到锅中)
我们通过函数/生成器来实现这一切,不需要使用复杂的类或类似的东西
结构。
运行总数
我们可以使用生成器来跟踪发送给它的值的运行总数。
任何时候我们添加一个数字,输入的计数和总数返回(有效
之前的输入被发送到它的那一刻)。
from collections import namedtuple
RunningTotal = namedtuple("RunningTotal", ["n", "total"])
def runningtotals(n=0, total=0):
while True:
delta = yield RunningTotal(n, total)
if delta:
n += 1
total += delta
if __name__ == "__main__":
nums = [9, 8, None, 3, 4, 2, 1]
bookeeper = runningtotals()
print bookeeper.next()
for num in nums:
print num, bookeeper.send(num)
输出如下所示:
RunningTotal(n=0, total=0)
9 RunningTotal(n=1, total=9)
8 RunningTotal(n=2, total=17)
None RunningTotal(n=2, total=17)
3 RunningTotal(n=3, total=20)
4 RunningTotal(n=4, total=24)
2 RunningTotal(n=5, total=26)
1 RunningTotal(n=6, total=27)