在for循环上下文中使用try-except时,到目前为止执行的命令显然是用
完成的a = [1, 2, 3, 'text', 5]
b = []
try:
for k in range(len(a)):
b.append(a[k] + 4)
except:
print('Error!')
print(b)
的结果
Error!
[5, 6, 7]
然而,列表推导不一样
c=[]
try:
c = [a[k] + 4 for k in range(len(a))]
except:
print('Error!')
print(c)
结果是
Error!
[]
在发生异常之前构建的中间列表是否保留在任何位置?它可以访问吗?
答案 0 :(得分:26)
列表推导中间结果保存在内部CPython堆栈中,并且无法从列表推导中的Python表达式访问。
请注意,Python执行[.....]
第一个,它会生成一个列表对象,只有然后会将该结果分配给名称c
。如果[....]
表达式中发生异常,则表达式将终止,异常处理将启动。因此,您的print(c)
表达式只能显示c
绑定到的上一个对象,这里是一个空列表对象。它可能是其他任何东西:
>>> c = 'Anything else'
>>> try:
... c = [2 // i for i in (1, 0)]
... except ZeroDivisionError:
... pass
...
>>> c
'Anything else'
在第一个示例中,不会生成新的列表对象。您反而操纵(使用b.append()
)现有的列表对象,这就是为什么您可以看到所有成功的b.append()
调用已对其执行的操作。
答案 1 :(得分:11)
让我们看看字节码:
>>> def example():
... c=[]
... try:
... c = [a[k] + 4 for k in range(len(a))]
... except:
... print('Error!')
... print(c)
...
>>> import dis
>>> dis.dis(example)
--- removed some instructions
27 GET_ITER
>> 28 FOR_ITER 20 (to 51)
31 STORE_FAST 1 (k)
34 LOAD_GLOBAL 2 (a)
37 LOAD_FAST 1 (k)
40 BINARY_SUBSCR
41 LOAD_CONST 1 (4)
44 BINARY_ADD
45 LIST_APPEND 2
48 JUMP_ABSOLUTE 28
>> 51 STORE_FAST 0 (c)
--- more instructions...
如您所见,列表推导被转换为一系列指令GET_ITER
... JUMP_ABSOLUTE
。下一条指令STORE_FAST
是修改c
的指令。如果在它之前发生任何异常,则c
将不会被修改。