50

这是我遇到问题的 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。为什么Pythoni中循环中的值不变,有for什么补救措施来获得预期的输出?

4

10 回答 10

52

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
于 2013-03-12T13:56:44.103 回答
24

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

这部分创建一个 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)

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

在这里您可以看到堆栈的顶部被弹出并分配给i

         19 STORE_FAST               0 (i)

所以i无论你在循环中做什么都会被覆盖。

如果您以前没有见过,这里是堆栈机器的概述。

于 2013-03-12T14:11:13.583 回答
17

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
于 2013-03-12T13:57:19.757 回答
5

如果由于某种原因您确实想将 add 3 更改为i等于5,并跳过下一个元素(这是在 C 3 元素中推进指针的一种),那么您可以使用迭代器并从中消耗一些位:

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
于 2013-03-12T14:05:08.980 回答
3

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

不是当您迭代 range(1, 10) 时,最终您是从列表类型对象中读取数据,并且每次到达 for 循环时 i 都会采用新值。

这类似于:

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

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

于 2019-02-23T11:19:46.270 回答
1

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

于 2013-03-12T13:56:33.357 回答
1

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

这在教程中有很好的描述。

于 2013-03-12T13:56:40.593 回答
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
于 2013-03-12T16:27:16.440 回答
1

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

for i in range (0,10):
    if i in [5, 6, 7]:
        continue
    print(i)
于 2019-02-23T11:04:33.063 回答
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
于 2018-08-07T03:46:26.217 回答