The 语法规则为for loops https://docs.python.org/3/reference/compound_stmts.html#the-for-statement允许迭代变量是其中指定的任何变量target_list
:
for_stmt ::= "for" target_list "in" expression_list ":" suite
["else" ":" suite]
where target_list allows https://docs.python.org/3/reference/simple_stmts.html#assignment-statements对于以下结构:
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
实质上为每次迭代执行赋值语句,如参考文献中所述:
每个项目依次分配到目标列表使用标准作业规则(请参阅赋值语句),然后执行套件。
所以循环的作用是,它从expression_list
并对每个值进行赋值target_list
。本质上等价于下面的while
loop:
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
and l[i]
.
如果你也拆机dis('i, l[i] = (1, 2)')
你会发现,如果你忽略元组的初始加载(1, 2)
和返回值,操作完全一样。