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-loops 的副产品,本质上是为每次迭代执行赋值语句,如参考中所述:
每个项目依次分配到目标列表使用分配的标准规则(请参阅分配语句),然后执行套件。
所以循环的作用是,它从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)的初始加载和值的返回,操作是完全一样的。