2013-05-08 147 views
0

考虑以下功能;懒惰评估发电机

def myfunc(): 
    a=b=c=0 
    x='12' 
    a,b,c=(i for i in x) 
    return a,b,c 

该函数抛出以下异常:ValueError:需要多于2个值才能解包。 我的意图是将“x”变量中的可用值分配给给定顺序左侧的变量。因此a = 1,b = 2,c = 3,我想要做什么。

为了提高我对发电机的理解,我拆开功能

>>> dis.dis(myfunc) 
    2   0 LOAD_CONST    1 (0) 
       3 DUP_TOP    
       4 STORE_FAST    0 (a) 
       7 DUP_TOP    
       8 STORE_FAST    1 (b) 
      11 STORE_FAST    2 (c) 

    3   14 LOAD_CONST    2 ('12') 
      17 STORE_FAST    3 (x) 

    4   20 LOAD_CONST    3 (<code object <genexpr> at 0x297b430, file "<stdin>", line 4>) 
      23 MAKE_FUNCTION   0 
      26 LOAD_FAST    3 (x) 
      29 GET_ITER    
      30 CALL_FUNCTION   1 
      33 UNPACK_SEQUENCE   3 
      36 STORE_FAST    0 (a) 
      39 STORE_FAST    1 (b) 
      42 STORE_FAST    2 (c) 

    5   45 LOAD_FAST    0 (a) 
      48 LOAD_FAST    1 (b) 
      51 LOAD_FAST    2 (c) 
      54 BUILD_TUPLE    3 
      57 RETURN_VALUE 

我猜是UNPACK_SEQUENCE被抛出异常。在UNPACK_SEQUENCE之前可以做STORE_FAST吗?希望我的问题有道理。

+2

'x ='12''不是''123''并且不,右手边总是先评估 – jamylak 2013-05-08 10:31:56

回答

2

您正在使用解包分配到三个不同的变量。拆箱迭代右侧的序列,以便这样做。

UNPACK_SEQUENCE的确抛出异常,因为你的发电机表达仅产生值,字符串'1''2',但你的左侧列表中的名称有名。

这不是发电机的问题。这是元组分配的限制,explicitly documented

a, b, c = list(x) 

抛出相同的异常,除非x是长度3,例如:

  • If the target list is a comma-separated list of targets: The object must be an iterable with the same number of items as there are targets in the target list, and the items are assigned, from left to right, to the corresponding targets.

相同的错误将使用列表时被抛出x = '123'

您可以自由发电机表达分配给一个变量:

>>> x = '12' 
>>> a = (i for i in x) 
>>> a 
<generator object <genexpr> at 0x105046dc0> 

如果您预计c仍然设置为0由于发电机无法提供足够的值,那么也不怎么样元组赋值工作。

你可以使用一个辅助功能为默认设置为:

def helper(a=0, b=0, c=0): 
    return a, b, c 

a, b, c = helper(*(i for i in x)) 

演示:

>>> def helper(a=0, b=0, c=0): 
...  return a, b, c 
... 
>>> a, b, c = helper(*(i for i in x)) 
>>> a, b, c 
('1', '2', 0) 

的辅助函数使用缺省值的所有参数,以及*调用语法使用发电机将这些视为位置参数。

+0

我明白了,有没有办法产生一个解压缩并实际分配给变量? – sardok 2013-05-08 10:37:04

+2

@sardok:你期望在这里分配什么?您可以只将生成器分配给左侧的**一个**名称,但应将其他两个名称分配给哪个名称? – 2013-05-08 10:37:57

+0

我明白了,谢谢澄清。我意识到我正在寻找一个答案,像a,b,c = 1,2保留c的值,但是分配a和b,看起来不可能。 – sardok 2013-05-08 10:52:01