Python 3:生成器的send方法

2024-05-16 06:23:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我无法理解send方法。我知道它是用来操作发电机的。但是 语法如下:generator.send(value)

我不知怎么搞不懂为什么值应该成为当前yield表达式的结果。我准备了一个例子:

def gen():
    for i in range(10):
        X = yield i
        if X == 'stop':
            break
        print("Inside the function " + str(X))

m = gen()
print("1 Outside the function " + str(next(m)) + '\n')
print("2 Outside the function " + str(next(m)) + '\n')
print("3 Outside the function " + str(next(m)) + '\n')
print("4 Outside the function " + str(next(m)) + '\n')
print('\n')
print("Outside the function " + str(m.send(None)) + '\n') # Start generator
print("Outside the function " + str(m.send(77)) + '\n')
print("Outside the function " + str(m.send(88)) + '\n')
#print("Outside the function " + str(m.send('stop')) + '\n')
print("Outside the function " + str(m.send(99)) + '\n')
print("Outside the function " + str(m.send(None)) + '\n')

结果是:

1 Outside the function 0

Inside the function None
2 Outside the function 1

Inside the function None
3 Outside the function 2

Inside the function None
4 Outside the function 3



Inside the function None
Outside the function 4

Inside the function 77
Outside the function 5

Inside the function 88
Outside the function 6

Inside the function 99
Outside the function 7

Inside the function None
Outside the function 8

坦白地说,这让我很吃惊。

  1. 在文档中,我们可以看到当执行yield语句时,生成器的状态被冻结,并且expression_list的值返回给next的调用方。 嗯,好像没发生过。为什么我们可以在gen()内部执行if语句和print函数。
  2. 我如何理解函数内部和外部的X为什么不同? 好 啊。假设send(77)将77传输到m。好吧,yield表达式变成77。 那么什么是X = yield i?函数内部的77在外部发生时如何转换为5?
  3. 为什么第一个结果字符串没有反映生成器中发生的任何事情?

不管怎样,你能对这些sendyield语句做些评论吗?


Tags: the函数nonesend表达式function语句generator
3条回答

最令人困惑的部分应该是这一行X = yield i,特别是当您在生成器上调用send()时。实际上你只需要知道:

在词汇层面: next()等于send(None)

在解释器级别: X = yield i等于下面的行(顺序问题):

yield i
# won't continue until next() or send() is called
# and this is also the entry point of next() or send()
X = the_input_of_send

而且,这两行注释正是我们需要第一次调用send(None)的原因,因为生成器将返回i(yieldi,然后再将值赋给X

def gen():
    i = 1
    while True:
        i += 1
        x = yield i
        print(x)

m = gen()
next(m)
next(m)
m.send(4)

结果

None
4

请看上面更简单的代码。
我想导致你困惑的是“x=屈服I”声明, 这个语句并不是说从send()方法中接受的值,该方法被设为i,然后我被设为x。 相反,yield语句将值i返回给生成器,x由send()方法生成。一个语句同时执行两个操作。

当您在生成器中使用send和表达式yield时,您将其视为一个协程;一个单独的执行线程,可以按顺序交错运行,但不能与其调用方并行。

当调用方执行R = m.send(a)时,它将对象a放入生成器的输入槽中,将控制权传递给生成器,并等待响应。生成器接收作为X = yield i结果的对象a,并运行,直到它碰到另一个yield表达式,例如Y = yield j。然后它将j放入其输出槽,将控制权传输回调用方,并等待它再次恢复。调用者接收j作为R = m.send(a)的结果,并一直运行,直到它碰到另一个S = m.send(b)语句,依此类推。

R = next(m)R = m.send(None)一样;它将None放入生成器的输入槽中,因此如果生成器检查X = yield i的结果,那么X将是None

作为一个隐喻,考虑一个dumb waiter

Dumb waiter

当服务生接到顾客的订单时,他们把便笺簿放进哑服务生的房间,然后把便笺簿放进厨房,在舱口等菜:

R = kitchen.send("Ham omelette, side salad")

厨师(一直在舱口旁边等着)拿起订单,准备好菜,把它送到餐厅,然后等待下一个订单:

next_order = yield [HamOmelette(), SideSalad()]

服务员(一直在舱口等着)把菜拿给顾客,然后拿着另一份订单等回来

因为服务器和厨师在点餐或上菜后都在舱口等候,所以在同一时间只有一个人在做任何事情,也就是说,这个过程是单线程的。双方可以使用正常的控制流程,因为发电机机械(哑服务员)负责交织执行。

相关问题 更多 >