for循环中的python变量的范围

时间:2013-03-12 13:53:29

标签: python for-loop scope

下面是我遇到问题的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中的变量创建了一个新的范围,但不知道python。任何人都可以解释为什么i的值在python中的for循环中没有变化,并且为了得到预期的输出有什么补救措施。

10 个答案:

答案 0 :(得分:32)

for循环遍历range(10)中的所有数字,即[0,1,2,3,4,5,6,7,8,9] 您更改i当前值对该范围中的下一个值没有影响。

您可以使用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

答案 1 :(得分:18)

与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不会产生预期效果。

反汇编示例

您可以查看disassembly of the python code以查看此内容:

>>> 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        
>>> 

这部分creates a range between 0 and 10并实现它:

          3 LOAD_GLOBAL              0 (range)
          6 LOAD_CONST               1 (0)
          9 LOAD_CONST               2 (10)
         12 CALL_FUNCTION            2

此时,堆栈顶部包含范围。

gets an iterator over the object on the top of the stack,即范围:

         15 GET_ITER  

此时,堆栈顶部包含一个超出实现范围的迭代器。

FOR_ITER begins iterating over the loop使用estack顶部的迭代器:

    >>   16 FOR_ITER                36 (to 55)

此时,堆栈顶部包含迭代器的下一个值。

在这里你可以看到the top of the stack is popped and assigned to i

         19 STORE_FAST               0 (i)

无论你在循环中做什么,都会覆盖i

如果您之前没有看过,请参阅overview of stack machines

答案 2 :(得分:14)

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

答案 3 :(得分:4)

如果由于某种原因你确实想要在i等于5时将其添加到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 ,并跳过下一个元素(这有点推动C 3元素中的指针),那么你可以使用一个迭代器并从中消耗掉几个位:

{{1}}

答案 4 :(得分:1)

我每次迭代都会重置,因此在循环中对你所做的事情并不重要。唯一一次它做任何事情是当我是5,然后它增加3。一旦它循环回来,然后将我设置回列表中的下一个数字。你可能想在这里使用while

答案 5 :(得分:1)

Python的for循环只是循环遍及提供的值序列 - 将其视为“foreach”。因此,修改变量对循环执行没有影响。

the tutorial中详细描述了这一点。

答案 6 :(得分:1)

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

答案 7 :(得分:1)

在python 2.7范围函数中,创建一个列表,而在python 3.x版本中,它创建一个“范围”类对象,该对象仅可迭代而不是列表,类似于python 2.7中的xrange。

不是在遍历range(1,10)时,最终您正在从列表类型对象中读取数据,并且每次到达循环时我都会获取新值。

这类似于:

for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
    if i==5:
        i+=3
    print(i)

更改值不会更改列表中的迭代顺序。

答案 8 :(得分:0)

在我看来,类似的代码不是while循环,而是for循环,您可以在运行时在其中编辑列表:

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

答案 9 :(得分:0)

您可以对for循环进行以下修改:

for i in range (0,10):
    if i in [5, 6, 7]:
        continue
    print(i)