1

我希望从生成器中只需要尽可能多的项目。

在下面的代码中

a, b, c = itertools.count()

我收到此异常:

ValueError: too many values to unpack

我已经看到了几个相关的问题,但是我对生成器的剩余物品的兴趣为零,我只希望收到我要求的数量,而不是提前提供那个数量

在我看来,Python 确定了您想要的项目数量,但随后继续尝试读取和存储超过该数量的项目(生成ValueError)。

我怎样才能只生产我需要的数量,而不传递我想要的数量?

更新0

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

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 的回答向我表明字节操作UNPACK_SEQUENCE是造成限制的原因。我不明白为什么这个操作应该要求生成的序列也必须在长度上完全匹配。

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

4

4 回答 4

6

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

from itertools import islice
a, b, c = islice(itertools.count(), 3)
于 2010-06-18T13:58:16.203 回答
6

您需要深入的字节码破解- 您的请求无法在 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您自己的功能在哪里,易于实现(例如 via itertools.slice)。因此,原始的 2 字节码“快速加载;调用函数”序列(就在 unpack-sequence 字节码之前)必须成为这种 5 字节码序列,limit在原始序列之前有一个加载全局字节码,在load-const; call function之后的序列它。

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

或者(出于一般性目的)您可以更改函数的原始源,例如通过解析和更改 AST,并重新编译为字节码(当然,这确实需要源在装饰时可用)。

这值得生产使用吗?绝对不是,当然——对于微小的“语法糖”改进来说,工作量太荒谬了。但是,它可能是一个具有启发性的项目,可以帮助您精通字节码黑客、ast 黑客和其他您可能永远不需要的黑魔法技巧,但当您想超越单纯的语言向导的语言时,知道这些技巧肯定很酷世界级的大师——事实上,我怀疑那些有动力成为大师的人通常是不能不屈服于这种“语言内部机制”的迷恋的人......它达到那个崇高的水平是足够聪明的子集意识到这样的努力是“只是玩”,并将它们作为一种业余时间活动(精神上相当于举重,就像数独或填字游戏;-)而不让他们干扰重要任务(通过部署可靠、清晰、简单、性能良好、经过良好测试、记录良好的代码为用户提供价值,通常甚至没有丝毫的黑魔法暗示;-)。

于 2010-06-18T14:49:19.660 回答
3

Python 不能按照你想要的方式工作。在任何任务中,比如

a, b, c = itertools.count()

先评估右侧,再评估左侧。除非您告诉它,否则右侧无法知道左侧有多少项目。

于 2010-06-18T14:21:21.873 回答
1

或者使用列表推导,因为您知道所需的项目数量:

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

甚至更简单:

a,b,c = range(3)
于 2010-06-18T16:47:22.467 回答