产量只有发电机所需的数量

时间:2010-06-18 13:53:37

标签: python generator yield python-2.x

我希望只从需要很多项目的生成器中获得。

在以下代码中

a, b, c = itertools.count()

我收到此例外:

ValueError: too many values to unpack

我已经看过几个相关的问题,但是我对发电机剩余的项目没有兴趣,我只希望收到我要求的数量,没有事先提供数量

在我看来,Python确定了你想要的项目数,但后来尝试阅读和存储的数量超过了这个数量(生成ValueError)。

如何在不传递我想要多少项目的情况下,根据需要生成任意数量的项目?

Update0

为了帮助理解我认为应该可行的近似行为,这里是一个代码示例:

def unpack_seq(ctx, items, seq):
    for name in items:
        setattr(ctx, name, seq.next())

import itertools, sys
unpack_seq(sys.modules[__name__], ["a", "b", "c"], itertools.count())
print a, b, c

如果您可以改进此代码,请执行。

Alex Martelli's answer向我建议字节op UNPACK_SEQUENCE负责限制。我不明白为什么这个操作应该要求生成的序列在长度上也必须完全匹配。

请注意,Python 3具有不同的解包语法,这可能会使此问题中的技术讨论失效。

4 个答案:

答案 0 :(得分:6)

您需要确保双方的物品数量匹配。一种方法是使用itertools模块中的islice

from itertools import islice
a, b, c = islice(itertools.count(), 3)

答案 1 :(得分:6)

您需要一个深bytecode hack - 您要求的内容无法在Python源代码级别完成,但是(如果您愿意提交特定版本和Python版本)可以通过后处理来完成Python编译后的字节码。考虑一下,例如:

>>> def f(someit):
...   a, b, c = someit()
... 
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (someit)
              3 CALL_FUNCTION            0
              6 UNPACK_SEQUENCE          3
              9 STORE_FAST               1 (a)
             12 STORE_FAST               2 (b)
             15 STORE_FAST               3 (c)
             18 LOAD_CONST               0 (None)
             21 RETURN_VALUE        
>>> 

如您所见,UNPACK_SEQUENCE 3字节码发生时没有给出迭代器someit最少的指示(迭代器已被调用!) - 所以你必须在字节码中加上前缀“获得完全N字节”操作,例如:

>>> def g(someit):
...   a, b, c = limit(someit(), 3)
... 
>>> dis.dis(g)
  2           0 LOAD_GLOBAL              0 (limit)
              3 LOAD_FAST                0 (someit)
              6 CALL_FUNCTION            0
              9 LOAD_CONST               1 (3)
             12 CALL_FUNCTION            2
             15 UNPACK_SEQUENCE          3
             18 STORE_FAST               1 (a)
             21 STORE_FAST               2 (b)
             24 STORE_FAST               3 (c)
             27 LOAD_CONST               0 (None)
             30 RETURN_VALUE        

其中limit是您自己的功能,很容易实现(例如通过itertools.slice)。因此,原始的2字节代码“加载快速;调用函数”序列(在解包序列字节码之前)必须成为这种5字节码序列,在原始序列之前具有limit的加载全局字节码,以及之后的load-const; call function序列。

您当然可以在装饰器中实现此字节码。

或者(为了一般性)你可以改变函数的原始来源,例如:通过解析和更改AST,并重新编译为字节代码(但这确实需要在装饰时提供源代码)。

这是否适合生产用途?当然,绝对不是 - 对于一个微小的“语法糖”改进的荒谬工作量。然而,它可能是一个有益的项目,以获得掌握字节码黑客,恶意黑客和其他黑魔法技巧,你可能永远不会需要,但肯定很酷,知道什么时候你想超越单纯的语言向导的语言世界级大师的确 - 我确实怀疑那些有动力成为大师的人通常是那些不能屈服于这种“语言内部”机制的魅力的人......而那些真正的人使其达到崇高程度是足够智慧的子集,以实现这种努力“只是玩”,并将其作为一项业余活动(精神等同于举重,就像说数独或填字游戏; - )不让他们干扰重要任务(通过部署稳固,清晰,简单,性能良好,经过良好测试,记录良好的代码为用户提供价值,通常没有甚至是最轻微的提示对它的黑魔法; - )。

答案 2 :(得分:3)

Python无法按您的方式工作。在任何作业中,例如

a, b, c = itertools.count()

the right-hand side is evaluated first,在左侧之前。 除非你说出来,否则右手边无法知道左手边有多少物品。

答案 3 :(得分:1)

或使用列表理解,因为您知道所需的项目数:

ic = itertools.count()
a,b,c = [ic.next() for i in range(3)]

甚至更简单:

a,b,c = range(3)