【问题标题】:Python For Loop List Interesting ResultPython For 循环列表有趣的结果
【发布时间】:2013-01-06 02:23:08
【问题描述】:
a = [0,1,2,3,4,5]
for b in a:
  print ":"+str(b)
  a.pop(0)

认为这可以按顺序遍历整个列表及其所有项目,因此我运行了此代码并预料到了这一点。

:0
0
:1
1
:2
2
:3
3
:4
4
:5
5

相反,我得到了这个:

:0
0
:2
1
:4
2

现在我明白为什么会这样了,但这是 python 中的错误吗?它不应该仍然遍历所有原始对象而不是当前列表的长度吗?为什么这没有抛出和越界错误? IE:不应该还是做吗:

:0
0
:1
2
:2
4
:3
Error
:4
Error
:5
Error

【问题讨论】:

    标签: python python-2.7


    【解决方案1】:

    这完全是“预期的”并记录在案的行为。当您遍历列表时,您基本上是在遍历内存位置。当您从列表中弹出某些内容时,列表中之后的所有内容都会将 1 个索引移到更靠近列表开头的位置。因此,您最终会跳过项目。到达列表末尾时迭代停止。

    通常在执行此类操作时,您希望遍历列表的副本:

    for b in a[:]:
        ...
    

    如 cmets 所示,如果您以相反的顺序遍历列表:

    for b in reversed(a):
        a.pop()
    

    这是按预期工作的,因为您不断地拉出最后一个元素,因此您不会改变您尚未看到的任何元素列表中的位置。

    【讨论】:

    • 另一种在某些情况下有用的方法是以相反的顺序进行迭代:for b in reversed(a)
    • @kindall -- 感谢您的评论。我已将该信息纳入我的答案中。
    • -1 是.pop() 的默认参数,因此您可以安全地省略它。
    • @MartijnPieters -- try: Make_me_feel_better_argument("Explicit is better than implicit"); except FeelBetterError: update_post()
    【解决方案2】:

    您正在遍历一个列表并同时对其进行更改。通过使用.pop(),您正在缩短列表,但迭代器指针不会更新。

    改用副本:

    for b in list(a):
    

    或

    for b in a[:]:
    

    [:] 切片表示法返回列表副本。

    另一种方法是改用while 循环:

    while a:
        print a.pop(0)
    

    因为空列表测试为布尔值False。

    python for 循环使用它的参数作为迭代器,它本身并不保留索引。 for 循环无法“知道”您删除了元素。相反,保留该指针的是 list() 迭代器:

    >>> a = [0,1,2,3,4,5]
    >>> itera = iter(a)
    >>> itera.next()  # index 0 -> a[0] is 0
    0
    >>> a.pop(0)
    0
    >>> a
    [1,2,3,4,5]
    >>> itera.next()  # index 1 -> a[1] is 2
    2
    

    该迭代器保留一个计数器,每次您在迭代器上调用 next() 时,它都会为您提供下一个索引处的值,无论该值可能是什么,直到计数器相等到列表的当前长度。

    【讨论】:

    • 我已经明白为什么了,但这不应该是报错吗?
    • 哦,我忘记了列表正在缩短,但它仍然是列表的长度而不是每个元素。
    • "你不能在遍历一个列表的同时改变它。"你可以,但它不会像你想要的那样工作。
    【解决方案3】:

    如果你想在循环中使用.pop(),一个常见的习惯用法是与while一起使用:

    a = [0,1,2,3,4,5]
    while a:
      print ":{}".format(a.pop(0))
    

    或者,如果您想要打印的图案:

    a = [0,1,2,3,4,5]
    while a:
        print ":{}\n{}".format(a[0],a.pop(0))
    

    打印

    :0
    0
    :1
    1
    :2
    2
    :3
    3
    :4
    4
    :5
    5
    

    【讨论】:

      【解决方案4】:

      在for 循环的每次迭代中,我们必须检查条件b in a 所以当你开始时:

      a = [0,1,2,3,4,5]
      for b in a:
        print ":"+str(b)
        a.pop(0)
      

      b = 0 和 in a(表示 a 中的元素)是 5。现在打印a[b] 的字符串化版本,然后删除数组的第一个元素。因此迭代二变为:

      a = [1, 2, 3, 4, 5]
      b = 1 (it incremented)
      size of a = 4 (it shrank)
      

      接下来它们将是b=2,a 的大小变为 3。最终的迭代会产生您所期望的越界错误,不会发生,因为 b 将大于数组,所以我们完成了。

      【讨论】:

        猜你喜欢
        • 2020-07-02
        • 1970-01-01
        • 2015-08-24
        • 1970-01-01
        • 2014-10-24
        • 2019-09-05
        • 2018-09-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多