Scope of python variable in for loop
下面是我遇到问题的python代码:
1 2 3 4 | for i in range (0,10): if i==5: i+=3 print i |
我预计产量为:
1 2 3 4 5 6 7 | 0 1 2 3 4 8 9 |
然而,译员吐出:
1 2 3 4 5 6 7 8 9 10 | 0 1 2 3 4 8 6 7 8 9 |
我知道
for循环迭代
您可以通过while循环获得所需的行为。
1 2 3 4 5 6 7 8 9 10 | 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码
您想象的是,您在python中的
1 2 3 | for (int i = 0; i < 10; i++) if (i == 5) i += 3; |
它更像是C代码:
1 2 3 4 5 6 | 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; } |
所以在循环中修改
您可以查看python代码的反汇编来了解这一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | >>> 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 >>> |
此部分创建0到10之间的范围并实现:
1 2 3 4 | 3 LOAD_GLOBAL 0 (range) 6 LOAD_CONST 1 (0) 9 LOAD_CONST 2 (10) 12 CALL_FUNCTION 2 |
此时,堆栈顶部包含范围。
这将在堆栈顶部的对象上获取一个迭代器,即范围:
1 | 15 GET_ITER |
此时,堆栈顶部包含一个已实现范围内的迭代器。
对于"Iter",使用位于堆栈顶部的迭代器开始循环迭代:
1 | >> 16 FOR_ITER 36 (to 55) |
此时,堆栈顶部包含迭代器的下一个值。
在这里,您可以看到栈顶被弹出并分配给
1 | 19 STORE_FAST 0 (i) |
因此,无论您在循环中做什么,
如果您以前没有看到这个,这里是堆栈机器的概述。
python中的for循环实际上是for each循环。在每个循环的开始,
也就是说,您编写的
1 2 3 4 5 6 7 8 9 10 11 12 | _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 |
如果出于某种原因,您真的想在等于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |
在python 2.7 range函数中创建一个列表,而在python 3.x版本中,它创建一个"range"类对象,该对象只能是不可迭代的,而不是列表,类似于python2.7中的xrange。
当您在范围(1,10)内迭代时,并不是这样,最终您将从列表类型对象中读取,并且每次到达for循环时,我都获取新的值。
这类似于:
1 2 3 4 | for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: if i==5: i+=3 print(i) |
更改值不会更改列表中的迭代顺序。
1 2 3 4 | it = iter(xrange (0,10)) for i in it: if i==4: all(it.next() for a in xrange(3)) print i |
或
1 2 3 4 5 | it = iter(xrange (0,10)) itn = it.next for i in it: if i==4: all(itn() for a in xrange(3)) print i |
python的
这在本教程中有很好的描述。
每次迭代我都会重置,所以在循环中对它做什么并不重要。唯一一次它做任何事情是当我5岁的时候,然后它加3。一旦它循环返回,然后将我设置回列表中的下一个数字。您可能想在这里使用
您可以对您的
1 2 3 4 | for i in range (0,10): if i in [5, 6, 7]: continue print(i) |
在我看来,类似的代码不是while循环,而是for循环,在运行时编辑列表:
1 2 3 4 5 6 7 8 9 10 | originalLoopRange = 5 loopList = list(range(originalLoopRange)) timesThroughLoop = 0 for loopIndex in loopList: print(timesThroughLoop,"count") if loopIndex == 2: loopList.pop(3) print(loopList) print(loopIndex) timesThroughLoop += 1 |