对Python for loop行为和if语句

时间:2018-02-09 05:26:59

标签: python python-3.x

我希望有人可以向我解释这种行为以及发生了什么。

如果我运行以下代码:

phrase = "Don't Panic!"
phraseList = list(phrase)
print(phrase)
print(phraseList)

ontap = ['o', 'n', 't', 'a', 'p']

for letter in phraseList:
    print("Letter ", letter)
    #if letter not in ontap:
    #    phraseList.remove(letter)

print(phraseList)

我得到以下预期输出:

Don't Panic!
['D', 'o', 'n', "'", 't', ' ', 'P', 'a', 'n', 'i', 'c', '!']
Letter  D
Letter  o
Letter  n
Letter  '
Letter  t
Letter   
Letter  P
Letter  a
Letter  n
Letter  i
Letter  c
Letter  !
['D', 'o', 'n', "'", 't', ' ', 'P', 'a', 'n', 'i', 'c', '!']

但是,如果删除评论,我会收到这种意外行为:

Don't Panic!
['D', 'o', 'n', "'", 't', ' ', 'P', 'a', 'n', 'i', 'c', '!']
Letter  D
Letter  n
Letter  '
Letter   
Letter  a
Letter  n
Letter  i
Letter  !
['o', 'n', 't', 'P', 'a', 'n', 'c']

所以我的问题是,在循环中我希望PRINT首先在列表之前执行。 remove函数运行但似乎没有那样工作。为什么?它似乎是像字母C一样在字体中跳过字母。 另外,为什么比较似乎忽略了字母C,当它明显不在ontap变量中时。

我可能遗漏了一些非常明显的东西。它是否与调整列表大小并同时在其上运行循环有关?

感谢您的任何见解。

1 个答案:

答案 0 :(得分:0)

正如对该问题的评论所证实的那样,问题确实是在迭代它时修改phraseList。更详细一点,发生了什么:当你进入for循环时,会创建一个迭代器来迭代phraseList。在第一次迭代中,迭代器提供phraseList[0],即D。这不在ontap列表中,因此我们执行phraseList.remove('D')。在下一次迭代中,phraseList现在是['o', 'n', "'", 't', ...],但迭代器不知道它已被更改 - 它只知道它现在需要提供phraseList[1],现在是n }。这就是第二次迭代打印n而不是o的原因。永远不会从c移除phraseList,因为它出现的唯一位置是在第一次出现i之后。从i移除phraseList后,在下一个循环中,会跳过c。 (同样,P未被移除,因为它位于第一个<space>实例之后。)

修复循环的最简单方法是迭代phraseList的副本:

for letter in list(phraseList):
    print("Letter ", letter)
    if letter not in ontap:
        phraseList.remove(letter)

这样更改原始phraseList不会影响迭代。通过列表理解,您也可以更简洁(并且在我看来,更清晰)。以下内容完全实现了上面的for循环:

phraseList = [letter for letter in phraseList if letter in ontap]