Python中如何接受以下构造:
l = [1, 2, 3, 4]
for i, l[i] in enumerate(l[:]):
print(l[i])
似乎没有任何抱怨,并且很高兴地打印出1 2 3 4
。这是怎么允许的,它究竟是做什么的?
答案 0 :(得分:2)
syntax rule for for
loops允许迭代变量为target_list
中指定的任何变量:
for_stmt ::= "for" target_list "in" expression_list ":" suite
["else" ":" suite]
其中target_list
allows表示以下结构:
target_list ::= target ("," target)* [","]
target ::= identifier
| "(" [target_list] ")"
| "[" [target_list] "]"
| attributeref
| subscription
| slicing
| "*" target
这意味着您还可以执行其他古怪的事情,例如分配到切片:
for l[::-1] in [l, l, l]: pass
或订阅:
class Foo: a = 20
for Foo.a in range(2): pass
但我真的不知道你为什么要这样做。
这是for-loop
s的副产品,基本上为每次迭代执行赋值语句,如参考文献中所述:
依次使用分配的标准规则(参见赋值语句)将每个项目分配给目标列表,然后执行该套件。
循环的作用是,它从expression_list
获取迭代器,并对target_list
中的每个值执行赋值。基本上等同于以下while
循环:
it = enumerate(l[:])
while True:
try:
i, l[i] = next(it)
print(l[i])
except StopIteration:
break
dis
也可以显示在字节码级别上显示的此行为。使用略微简化的版本:
def _():
for i, l[i] in enumerate(l[:]):
pass
您的输出结果为:
dis(_)
2 0 SETUP_LOOP 40 (to 43)
3 LOAD_GLOBAL 0 (enumerate)
6 LOAD_GLOBAL 1 (l)
9 LOAD_CONST 0 (None)
12 LOAD_CONST 0 (None)
15 BUILD_SLICE 2
18 BINARY_SUBSCR
19 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
22 GET_ITER
>> 23 FOR_ITER 16 (to 42)
26 UNPACK_SEQUENCE 2
29 STORE_FAST 0 (i)
32 LOAD_GLOBAL 1 (l)
35 LOAD_FAST 0 (i)
38 STORE_SUBSCR
3 39 JUMP_ABSOLUTE 23
>> 42 POP_BLOCK
>> 43 LOAD_CONST 0 (None)
46 RETURN_VALUE
在FOR_ITER
命令之后立即执行相关赋值:
26 UNPACK_SEQUENCE 2
29 STORE_FAST 0 (i)
32 LOAD_GLOBAL 1 (l)
35 LOAD_FAST 0 (i)
38 STORE_SUBSCR
解压缩序列并将其分配给i
和l[i]
。
如果您还反汇编dis('i, l[i] = (1, 2)')
,您会看到如果忽略元组(1, 2)
的初始加载并返回值,则操作完全相同。