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

Mat*_*ner 1 python yield generator python-2.x

我希望只从需要许多物品的发电机中获益.

在以下代码中

a, b, c = itertools.count()
Run Code Online (Sandbox Code Playgroud)

我收到这个例外:

ValueError: too many values to unpack
Run Code Online (Sandbox Code Playgroud)

我已经看过几个相关的问题,但是我对发电机剩余的项目没有兴趣,我只想收到我要求的数量,而不提前提供这个数量.

在我看来,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
Run Code Online (Sandbox Code Playgroud)

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

Alex Martelli的回答告诉我,字节op UNPACK_SEQUENCE负责限制.我不明白为什么这个操作应该要求生成的序列在长度上也必须完全匹配.

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

Mar*_*ers 6

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

from itertools import islice
a, b, c = islice(itertools.count(), 3)
Run Code Online (Sandbox Code Playgroud)


Ale*_*lli 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        
>>> 
Run Code Online (Sandbox Code Playgroud)

如你所见,UNPACK_SEQUENCE 3字节码的出现没有给迭代器someit提供最少的指示(迭代器已被调用!) - 所以你必须在字节码中用"get n N bytes"操作作为前缀,例如:

>>> 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        
Run Code Online (Sandbox Code Playgroud)

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

你当然可以在装饰器中实现这个字节码.

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

这对于生产使用是否值得?当然,绝对不是 - 对于一个微小的"语法糖"改进的荒谬工作量.然而,它可能是一个有益的项目,以获得掌握字节码黑客,恶意黑客和其他黑魔法技巧,你可能永远不会需要,但肯定很酷,知道什么时候你想超越单纯的语言向导的语言世界级大师的确 - 我确实怀疑那些有动力成为大师的人通常是能够屈服于这种"语言内部"机制的魅力的人......以及那些真正做出的人它达到了崇高程度,足以明智地认识到这种努力是"只是玩",并将它们作为一项业余活动(精神等同于举重,就像数独或填字游戏;-)而不让它们干扰的重要任务(通过部署扎实,清晰,操作简单,性能良好的,经过严格测试的,证据充分的代码将价值传递给用户,经常连的黑魔法丝毫暗示它;-).