考虑以下功能;
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? 希望我的问题有道理。
答案 0 :(得分:2)
您使用解包分配三个不同的变量。解包有来迭代右手序列,以便这样做。
UNPACK_SEQUENCE
确实抛出异常,因为你的生成器表达式只产生两个值,字符串'1'
和'2'
,但你的左手名单列表中有 3个名称。
这对发电机来说不是问题。这是元组分配的限制,explicitly documented:
- 如果目标列表是以逗号分隔的目标列表:对象必须是与目标列表中的目标具有相同项目数的可迭代对象,并且项目将从左到右分配到相应的目标。
使用列表时会抛出相同的错误:
a, b, c = list(x)
除非x
长度为3,否则会抛出相同的异常,例如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)
辅助函数使用所有参数的默认值,*
调用语法使用生成器将这些作为位置参数处理。