【问题标题】:Common failure with while loops: why? [closed]while 循环的常见故障:为什么? [关闭]
【发布时间】:2016-05-24 09:38:17
【问题描述】:

我经常发现自己在处理类似于以下代码触发的故障的问题。如您所见,我在此示例中使用的对策是徒劳的:由于某种原因,while len(some_list) > n + 1 最终会给出“误报”。

当然,我可以使用pass 语句来覆盖这个“有趣的行为”(即使我认为它有点“hacky”,它会起作用)。然而,重点是:为什么会发生这种情况?

some_list = [2,3,2]

some_list.sort(reverse=True)

n = 0
while len(some_list) > 1 and n < len(some_list) - 1:
    try:
        while len(some_list) > n + 1:
            # This `if` statement was my last counter-measure
            if n + 1 >= len(some_list):
                break
            while some_list[n] == some_list[n+1]:
                some_list[n] += some_list.pop(n+1)
            else:
                n += 1
    except:
        print "WTF!!! len =",len(some_list),", n =",n
        raise

这是命令行的响应:

WTF!!! len = 2 , n = 1
  Traceback (most recent call last):
    File "example.py", line 11, in <module>
      while some_list[n] == some_list[n+1]:
IndexError: list index out of range

说明:

  • 我故意使用.pop() 来消除该元素。
  • 问题的目的是确定此类错误的原因,仅此而已。
  • 代码只是触发我想在问题中公开的异常的示例。
  • 代码的“目的”是消除列表重复项,将它们添加到相邻元素(预期相等)。

错误的猜测导致问题的表述错误

使用@Kevin M granger 推荐的调试器后:

-> while len(some_list) > n + 1:
(Pdb) print len(some_list), ">", n + 1
3 > 2
(Pdb) next
> /tmp/kpasa.py(10)<module>()
-> if n + 1 >= len(some_list):
(Pdb) print n + 1, ">=", len(some_list)
2 >= 3
(Pdb) next
> /tmp/kpasa.py(13)<module>()
-> while some_list[n] == some_list[n+1]:
(Pdb) print len(some_list), n
3 1
(Pdb) next
> /tmp/kpasa.py(14)<module>()
-> some_list[n] += some_list.pop(n+1)
(Pdb) next
> /tmp/kpasa.py(13)<module>()
-> while some_list[n] == some_list[n+1]:
(Pdb) print len(some_list), n
2 1
(Pdb) next
IndexError: 'list index out of range'

我意识到自己的愚蠢。根本没有“误报”。 这个问题其实很蠢,所以我同意必须删除它。

我很抱歉我的粗鲁和愚蠢。

【问题讨论】:

  • 这段代码的目的是什么?您的预期结果是什么?
  • 使用a debugger 逐行执行代码,同时监控变量及其值。
  • 另外,想想当n 等于列表中倒数第二个索引(在您的示例中为1)时会发生什么,并且您从列表中弹出最后一个元素。那么n + 1 将引用什么元素?
  • 代码本身并不重要。我正在尝试了解有关此问题的更多信息,仅此而已。但是,为了完整起见,此示例中的“目的”是消除列表重复项,将它们添加到相邻元素(预期相等)。我只是尽可能地隔离了这个问题。
  • Python 带有一个内置的调试器。 python -m pdb ./scriptname.py

标签: python loops while-loop


【解决方案1】:
while some_list[n] == some_list[n+1]:
    some_list[n] += some_list.pop(n+1)

这里的pop 减少了列表的长度,并且在下一次while 迭代中不能保证len(some_list) &gt; n + 1,所以会发生异常。您可以将内部while 更改为:

while len(some_list) > n + 1 and some_list[n] == some_list[n+1]:
    some_list[n] += some_list.pop(n+1)

【讨论】:

  • 即使通过您的方法解决了问题(顺便说一句,谢谢),为什么会产生“误报”的疑问仍然是个谜。我会试试调试器看看会发生什么,看看能不能找到答案……
  • @SebasSBM 没有“误报”。在外部 while 循环检查其长度后,您正在更改列表,因此该条件不再成立。
  • 几个小时前我才意识到。我留下了证据作为答案。我对此太粗鲁了,意识到我的错误花了我太长时间......
【解决方案2】:

你的麻烦就在这里:

while some_list[n] == some_list[n+1]:
    some_list[n] += some_list.pop(n+1)

当 n=1 时,您从 some_list 中弹出最后一项并将其添加到 some_list[1]。 “pop”修改了列表,所以现在 some_list 现在是 [3, 4]。然后返回“while”条件,检查 some_list[1] == some_list[2],但 some_list 在索引 2 处不再有项目;你刚刚弹出它。

这是一种不同的方法,看起来(至少在我看来)更清晰(尽管我猜测你想要做什么:

some_list = [2,3,2]

some_list.sort(reverse=True)

new_list = []
prior_value = None
for old_value in some_list:
    if old_value == prior_value:
        new_list[-1] += old_value
    else:
        new_list.append(old_value)
        prior_value = old_value

print new_list

【讨论】:

  • 这就是我一开始的想法,但即便如此,看起来它还是因为while len(some_list) &gt; n + 1: 返回了 True(while 2 &gt; 2 不应该)......我真的很困惑。 +1 的努力,它帮助我有更广泛的观点
【解决方案3】:

some_list[n] += some_list.pop(n+1) 行中,您减小了列表的大小。当它下一次评估 while some_list[n] == some_list[n+1]: 时,some_list[n+1] 会引发 IndexError,因为列表现在少于 n+​​1 个元素。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-17
    • 1970-01-01
    • 2016-07-27
    • 1970-01-01
    • 2021-08-17
    • 2016-10-16
    • 2017-09-16
    相关资源
    最近更新 更多