for循环中python变量的作用域

2024-05-23 13:37:13 发布

您现在位置:Python中文网/ 问答频道 /正文

以下是python代码im遇到的问题:

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一无所知。有谁能解释一下为什么python中的i循环中的for值没有变化,以及如何补救它以获得预期的输出。


Tags: 代码inforifrange作用域printim
3条回答

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

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

与C代码类似

你在想象你在python中的for-loop是这样的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使用位于堆栈顶部的迭代器:

    >>   16 FOR_ITER                36 (to 55)

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

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

         19 STORE_FAST               0 (i)

因此无论您在循环中做什么,都将覆盖i

这是一张overview of stack machines如果你以前没看过的话。

相关问题 更多 >