【问题标题】:What happens if you send() to a generator *expression* in Python?如果你 send() 到 Python 中的生成器 *expression* 会发生什么?
【发布时间】:2019-01-09 13:30:27
【问题描述】:

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

我的 99 去哪儿了? ge 中没有 yield 表达式,没有什么可以赋值的。注入的价值是被简单地丢弃(我怀疑),还是涉及一些神秘?

有人看过吗?

【问题讨论】:

    标签: python generator send


    【解决方案1】:

    就像你 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 和生成器具有非常相似的反汇编,并且在两者中,YIELD_VALUE 后面紧跟一个 POP_TOP,它丢弃从 send 发送的任何值。

    【讨论】:

    • @Jean-FrançoisFabre:是的,这与通过生成器函数创建的 genexp 或生成器相同。如问题中所述,第一个 send 参数必须是 None
    • 是的,刚刚注意到了!
    【解决方案2】:

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

    另一个相关的错误已在此处注释(第 32139885 页),应禁止在 genexps 中使用 yield 表达式,但事实并非如此。 ge=((yield x*x) for x in [1,2,3]) 的形式被接受,.send() 有效。

    send 返回的答案是内部可迭代元素和send 的参数的混合...被视为错误,并且在 3.7 中它应该表明它已被弃用。 (人们一致认为这令人困惑。)

    但我在 Python 3.7(Anaconda,Windows 64)中对其进行了测试,但没有收到弃用警告。无论如何,这似乎是一个真正的错误,而不是要弃用的功能。相信暂时没有什么好说的了……

    JK

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-16
      • 1970-01-01
      • 2012-08-29
      • 2016-08-28
      • 2011-09-17
      • 1970-01-01
      • 1970-01-01
      • 2019-02-14
      相关资源
      最近更新 更多