Python如何使用多个"发送"调用生成器?

时间:2017-12-16 23:59:20

标签: python python-3.x

关于类似事项有很多好问题,例如

python generator "send" function purpose?

What does the "yield" keyword do?

让我们回到"发送":

的定义
  

恢复执行并将值“发送”到生成器函数中。   value参数成为当前yield表达式的结果。   send()方法返回生成器产生的下一个值,或   如果生成器退出而不产生另一个,则引发StopIteration   值。当调用send()来启动生成器时,必须调用它   以None作为参数,因为没有yield表达式   可以收到值

但我觉得我错过了一些重要的事情。这是我的3 send次调用的示例,其中包括初始化生成器的None值的初始值:

def multiplier():
    while True:
        m = yield               # Line #3
        print('m = ' + str(m))  # Line #4
        yield str(m * 2)        # Line #5
        yield str(m * 3)        # Line #6

#------------------------

it = multiplier()

print('it.send(None): ')
print(str(it.send(None)))
print('--------------')

print('it.send(10): ')
print(it.send(10))
print('--------------')

print('it.send(100): ')
print(it.send(100))
print('--------------')

这是一个输出:

it.send(None): 
None
--------------
it.send(10): 
m = 10
20
--------------
it.send(100): 
30
--------------

问题:

  • 当我在第5行使用it.send(10)时会发生什么。要是我们 按照定义,生成器执行恢复。发电机 接受10作为输入值,并将其用于当前yield expression。我的示例中为yield str(m * 2),但后来m 设置为10。什么时候发生的。那是因为 在#3行中myield之间的引用?

  • 第6行it.send(10)会发生什么,为什么输出仍为30? 这是否意味着我之前的问题中的参考仅起作用 一旦

注意: 如果我稍微更改我的示例并在第5行和第6行之间添加一行m = yield,然后在next(it)之后使用print(it.send(10)) - 在这种情况下输出开始有意义:20和300

1 个答案:

答案 0 :(得分:2)

你的生成器函数有三个yield表达式,但你丢掉了其中两个(第5行和第6行)的值。如果你对那里的值做了一些事情,你会看到函数中使用的100。如果您继续运行示例,则第五次调用send会导致生成器将m更新为新值。

让我们在您的示例中查看执行send调用的代码,并查看生成器同时执行的操作:

it = multiplier()

此时,生成器对象已创建并保存到it。生成器代码尚未开始运行,它在函数代码的开头暂停。

print(str(it.send(None)))

这开始运行生成器函数的代码。发送的值必须为None,否则您将收到错误消息。该功能永远不会看到这个价值。使用next启动生成器更为常见,因为next(it)等同于it.send(None)

生成器函数一直运行到第3行,其中出现第一个yield。由于您没有产生任何特定值,因此send的返回值为None(打印出来)。

print(it.send(10))

此值将发送到生成器,并成为第3行yield表达式的值。因此10将存储为m,代码将在第4行打印出来生成器函数继续运行到第5行,它到达下一个yield表达式。由于它正在产生str(m * 2),因此调用代码获得"20"并打印出来。

print(it.send(100))

100值作为第4行yield的值发送到生成器中。该值被忽略,因为您没有使用yield作为表达式而是作为语句。就像将100单独放在一条线上一样,这是完全合法的,但可能不是很有用。代码继续到第5行,它产生str(m * 3)"30",由调用代码打印。

这就是你的驱动代码停止的地方,但是生成器仍处于活动状态,你可以向它发送更多的值(并获得更多的值)。您send生成器的下一个值也会被忽略,就像100一样,但是m之后的值会以while为新值yield生成器中的循环返回到顶部,并且到达了第3行send

我怀疑您在此代码中与yield的一些混淆与您使用n*2作为表达式和语句的事实有关。可能你不想同时做这两件事。通常,您要么关心发送到生成器的所有值,要么您不关心它们中的任何值。如果您想要同时产生多个值(例如n*3def multiplier(): print("top of generator") m = yield # nothing to yield the first time, just a value we get print("before loop, m =", m) while True: print("top of loop, m =", m) m = yield m * 2, m * 3 # we always care about the value we're sent print("bottom of loop, m =", m) print("calling generator") it = multiplier() print("calling next") next(it) # this is equivalent to it.send(None) print("sending 10") print(it.send(10)) print("sending 20") print(it.send(20)) print("sending 100") print(it.send(100)) ),则可以产生元组而不是单个项。

以下是您的代码的修改版本,我认为您可能更容易玩和理解:

.map