【问题标题】:Yield multiple values产生多个值
【发布时间】:2013-05-31 11:28:50
【问题描述】:

我们不能在 python 生成器函数中产生多个值吗?

例子,

In [677]: def gen():
   .....:     for i in range(5):
   .....:         yield i, i+1
   .....:         

In [680]: k1, k2 = gen()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-680-b21f6543a7e9> in <module>()
----> 1 k1, k2 = a()

ValueError: too many values to unpack

它的工作原理如下:

In [678]: b = a()

In [679]: list(b)
Out[679]: [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]

即使我这样做,结果也一样:

In [692]: def a():
    for i in range(5):
        yield i
        yield i+1

谢谢。

【问题讨论】:

    标签: python


    【解决方案1】:

    因为gen() 返回一个生成器(单个项目 - 所以它不能被解包为两个),它需要提前首先 来获取值...

    g = gen()
    a, b = next(g)
    

    它适用于list,因为这会隐式消耗生成器。

    我们可以进一步使它成为一个生成器吗?像这样的:

    g = gen();
    def yield_g():
        yield g.next();
        k1,k2 = yield_g();
    

    因此list(k1) 将提供[0,1,2,3,4]list(k2) 将提供[1,2,3,4,5]

    保留您现有的生成器,并使用 izip(或 zip):

    from itertools import izip
    k1, k2 = izip(*gen())
    

    【讨论】:

    • 更新:在 Python 3.x 中,itertools.izip 已被内置的zip 替换,因此最后一个代码块简单地变成了k1, k2 = zip(*gen)
    【解决方案2】:

    您的函数gen 返回一个生成器,而不是从您给出的示例判断您可能期望的值。如果您遍历生成器,则会产生成对的值:

    In [2]: def gen():
       ...:     for i in range(5):
       ...:         yield i, i+1
       ...:         
    
    In [3]: for k1, k2 in gen():
       ...:     print k1, k2
       ...:     
    0 1
    1 2
    2 3
    3 4
    4 5
    

    【讨论】:

    • 不是这样的。请参阅 Jon Clements 的回答。
    • 嗯,我的例子是相似的,因为它使用for-loop 推进生成器。我同意乔恩的回答更加详尽,并且对出了什么问题有更好的解释。不过,我仍然不明白我的答案被否决了。
    • 我们可以进一步把它变成一个生成器吗?像 g = gen(); def yield_g(): yield g.next(); k1,k2 = yield_g(); 这样的东西,因此 list(k1) 会给 [0,1,2,3,4]list(k2) [1,2,3,4,5]
    • 我对此投了反对票,因为它本质上是错误的。问题不在于 OP 没有在列表中使用他的生成器。问题是他误解了表达式gen() 返回的内容,而您没有做任何纠正。事实上,你似乎也有这种误解。确实,您的第一句话特别不正确-生成器gen 是一个函数。
    • @Marcin:我同意 gen() 是一个返回生成器的函数(我的第一句话确实是错误的)。尽管如此,我认为重要的是要提到生成器通常是迭代的,for-loop 是很自然的事情。我同意我的回答可以从更多解释中受益。
    【解决方案3】:

    使用yield from

    def gen():
        for i in range(5):
            yield from (i, i+1)
    
    [v for v in gen()]
    # [0, 1, 1, 2, 2, 3, 3, 4, 4, 5]
    

    python docs 说:

    当使用yield from &lt;expr&gt; 时,它将提供的表达式视为子迭代器。

    【讨论】:

    • 从 OP 给出的例子来看,我不认为yield from 是他们所追求的,
    • @AMC ,很抱歉我没有理解你的意思。
    【解决方案4】:

    两种解决方案都可以正常工作,以防您想从生成器返回多个值。

     def gen():
        for i in range(5):
            yield i, i+1
    

    解决方案 1:

     for values in gen():
         print(values[0],values[1])
    

    解决方案 2:

     for value1, value2 in gen():
         print(value1, value2)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-23
      • 1970-01-01
      • 2011-07-13
      • 1970-01-01
      • 2013-11-22
      相关资源
      最近更新 更多