for循环中的pythonvariables的作用域
下面的Python代码即时通讯有问题:
for i in range (0,10): if i==5: i+=3 print i
我预计输出是:
0 1 2 3 4 8 9
然而翻译吐出:
0 1 2 3 4 8 6 7 8 9
我知道一个for
循环为C中的variables创build一个新的范围,但不知道python。 任何人都可以解释为什么i
的值没有改变在for
循环python和最新的补救措施,以获得预期的输出。
for循环迭代range(10)
所有数字,即[0,1,2,3,4,5,6,7,8,9]
。
你改变我的当前值对范围中的下一个值没有影响。
您可以通过while循环获得所需的行为。
i = 0 while i < 10: # do stuff and manipulate `i` as much as you like if i==5: i+=3 print i # don't forget to increment `i` manually i += 1
用C代码类比
你正在想象你的for-loop
在python就像这样的C代码:
for (int i = 0; i < 10; i++) if (i == 5) i += 3;
这更像是这个C代码:
int r[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for (int j = 0; j < sizeof(r)/sizeof(r[0]); j++) { int i = r[j]; if (i == 5) i += 3; }
所以修改i
在循环中没有你期望的效果。
反汇编的例子
你可以看看反编译的Python代码来看看这个:
>>> from dis import dis >>> def foo(): ... for i in range (0,10): ... if i==5: ... i+=3 ... print i ... >>> dis(foo) 2 0 SETUP_LOOP 53 (to 56) 3 LOAD_GLOBAL 0 (range) 6 LOAD_CONST 1 (0) 9 LOAD_CONST 2 (10) 12 CALL_FUNCTION 2 15 GET_ITER >> 16 FOR_ITER 36 (to 55) 19 STORE_FAST 0 (i) 3 22 LOAD_FAST 0 (i) 25 LOAD_CONST 3 (5) 28 COMPARE_OP 2 (==) 31 POP_JUMP_IF_FALSE 47 4 34 LOAD_FAST 0 (i) 37 LOAD_CONST 4 (3) 40 INPLACE_ADD 41 STORE_FAST 0 (i) 44 JUMP_FORWARD 0 (to 47) 5 >> 47 LOAD_FAST 0 (i) 50 PRINT_ITEM 51 PRINT_NEWLINE 52 JUMP_ABSOLUTE 16 >> 55 POP_BLOCK >> 56 LOAD_CONST 0 (None) 59 RETURN_VALUE >>>
这部分创build一个介于0到10之间的范围,并实现它:
3 LOAD_GLOBAL 0 (range) 6 LOAD_CONST 1 (0) 9 LOAD_CONST 2 (10) 12 CALL_FUNCTION 2
此时,堆栈顶部包含范围。
这将得到堆栈顶部的对象的迭代器 ,即范围:
15 GET_ITER
此时,堆栈的顶部包含一个遍历实现范围的迭代器。
FOR_ITER开始使用迭代器顶部的迭代器遍历循环 :
>> 16 FOR_ITER 36 (to 55)
此时,堆栈顶部包含迭代器的下一个值。
在这里你可以看到堆栈的顶部被popup并分配给i
:
19 STORE_FAST 0 (i)
所以无论你在循环中做什么, i
都会被覆盖。
以下是堆栈机器的概述,如果你以前没有看到过。
Python中的for循环实际上是for-each循环。 在每个循环的开始, i
被设置为迭代器中的下一个元素( range(0, 10)
)。 i
的值在每个循环的开始被重新设置,所以在循环体中改变它并不会改变它在下一次迭代中的值。
也就是说,你写的for
循环相当于下面的while循环:
_numbers = range(0, 10) #the list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] _iter = iter(_numbers) while True: try: i = _iter.next() except StopIteration: break #--YOUR CODE HERE:-- if i==5: i+=3 print i
如果由于某种原因,你真的想改变,当它等于5
时加3,并跳过下一个元素(这是在C 3元素中推进指针的types),那么你可以使用迭代器并消耗一些比特从那个:
from collections import deque from itertools import islice x = iter(range(10)) # create iterator over list, so we can skip unnecessary bits for i in x: if i == 5: deque(islice(x, 3), 0) # "swallow up" next 3 items i += 3 # modify current i to be 8 print i 0 1 2 3 4 8 9
it = iter(xrange (0,10)) for i in it: if i==4: all(it.next() for a in xrange(3)) print i
要么
it = iter(xrange (0,10)) itn = it.next for i in it: if i==4: all(itn() for a in xrange(3)) print i
我每次迭代都会重置,所以在循环内部做什么并不重要。 唯一一次做任何事情的时候,我是5,然后它增加3。 一旦它循环回来,然后设置我回到列表中的下一个数字。 你可能想while
这里使用一段while
。
Python的for
循环只是简单地循环所提供的值序列 – 将其视为“foreach”。 因此,修改variables对循环执行没有影响。
这在教程中有很好的描述。