如果在Python中将send()发送到生成器* expression *,会发生什么情况?

时间:2018-08-01 21:18:35

标签: python generator send

我很惊讶地发现, ge=(x*x for x in [1,2,3]) 接受.send方法。像任何其他生成器一样,第一次调用的参数必须为None,但是其他调用的行为,例如ans=ge.send(99)似乎与ans=next(ge)相同。

我的99在哪里? ge中没有yield表达式,没有要分配的内容。注入的值只是被丢弃了(我怀疑),还是有些神秘?

有人看到吗?

2 个答案:

答案 0 :(得分:3)

与您send使用生成器函数创建的等效生成器相同:

def genfunc(outer_iterable):
    for x in outer_iterable:
        yield x*x

ge = genfunc([1, 2, 3])

也就是说send参数被丢弃。

我们可以反汇编字节码以进一步确认:

import dis

ge=(x*x for x in [1,2,3])

print('Genexp:')
dis.dis(ge)

def genfunc(outer_iterable):
    for x in outer_iterable:
        yield x*x

ge = genfunc([1, 2, 3])

print()
print('Generator function:')
dis.dis(ge)

Output

Genexp:
  3           0 LOAD_FAST                0 (.0)
        >>    3 FOR_ITER                15 (to 21)
              6 STORE_FAST               1 (x)
              9 LOAD_FAST                1 (x)
             12 LOAD_FAST                1 (x)
             15 BINARY_MULTIPLY
             16 YIELD_VALUE
             17 POP_TOP
             18 JUMP_ABSOLUTE            3
        >>   21 LOAD_CONST               0 (None)
             24 RETURN_VALUE

Generator function:
  9           0 SETUP_LOOP              23 (to 26)
              3 LOAD_FAST                0 (outer_iterable)
              6 GET_ITER
        >>    7 FOR_ITER                15 (to 25)
             10 STORE_FAST               1 (x)

 10          13 LOAD_FAST                1 (x)
             16 LOAD_FAST                1 (x)
             19 BINARY_MULTIPLY
             20 YIELD_VALUE
             21 POP_TOP
             22 JUMP_ABSOLUTE            7
        >>   25 POP_BLOCK
        >>   26 LOAD_CONST               0 (None)
             29 RETURN_VALUE

genexp和通过generator函数创建的generator具有非常相似的反汇编,在两者中,YIELD_VALUE之后紧跟着POP_TOP,该send丢弃了从 private void iAbout_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { DevExpress.Utils.About.frmAbout dlg = new DevExpress.Utils.About.frmAbout("~"); dlg.ShowDialog(); } 发送来的任何值

答案 1 :(得分:0)

谢谢大家。所以是的,send的arg被丢弃了,但是 accepted 的事实似乎是一个异常。

这里已经评论了另一个相关的错误(第32139885页),在genexps中应禁止yield表达式,但事实并非如此。格式为ge=((yield x*x) for x in [1,2,3]),并且.send()有效。

然后,send返回的答案是内部可迭代元素和send的args的混合...如果我没记错的话,GvR在Python 3.8中写道: yield表达式)将被视为错误,并且在3.7中应表明已弃用。 (人们同意这令人困惑。)

但是我在Python 3.7(Anaconda,Windows 64)中进行了测试,但没有收到过时警告。无论如何,这似乎是一个实际的错误,而不是不推荐使用的功能。我相信目前没有什么可说的了...

JK