为什么修改迭代变量不会影响后续迭代?

2024-12-18 08:39:00
admin
原创
145
摘要:问题描述:以下是我遇到问题的 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 我知道在 C 中循环会为变量创建一个...

问题描述:

以下是我遇到问题的 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

我知道在 C 中循环会为变量创建一个新的作用域,但对 Python 一无所知。为什么 Python 中循环中for的值不会改变?如何解决才能获得预期的输出?i`for`


请参阅如何在 for 循环期间修改列表条目?以了解如何修改原始序列。在 3.x 中,当然range会创建一个不可变对象,因此它仍然不起作用。


解决方案 1:

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

解决方案 2:

与 C 代码类似

你想象一下你的for-loopPython 代码就像这样的 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无论您在循环中做什么,它都会被覆盖。

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

解决方案 3:

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

解决方案 4:

如果由于某种原因你确实想i在它等于时将加 3 更改为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

解决方案 5:

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

当您迭代范围(1,10)时则不然,最终您将从列表类型对象中读取,并且每次到达循环时 i 都会获取新值。

这是这样的:

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

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

解决方案 6:

每次迭代时,I 都会被重置,因此在循环内对它做什么其实并不重要。它唯一起作用的时候是当 i 为 5 时,然后它会将 3 加到它上面。一旦它循环回来,它就会将 i 重新设置为列表中的下一个数字。您可能想while在这里使用 a。

解决方案 7:

Python 的for循环只是循环遍历所提供的值序列 — 可以将其视为“foreach”。因此,修改变量不会影响循环执行。

教程中对此进行了很好的描述。

解决方案 8:

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

解决方案 9:

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

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

解决方案 10:

在我看来,类似的代码不是 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
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用