python中的in运算符如何在它遍历的列表发生变化时表现出来

时间:2013-06-27 23:05:48

标签: python loops

我在尝试删除时遇到了一个有趣且令人费解的情况 列表中的所有空字符串。我第一次写下面的代码。

lst=['###','','@@@','','$$$','','','%%%','','&&&']
print "len:",len(lst)

iteration=1
for item in lst:
    print iteration,":",lst,":",len(lst),":","'%s'"%item
    if item!='':
        pass
    else:
        lst.remove(item)
    iteration+=1

它产生以下输出:

len: 10
1 : ['###', '', '@@@', '', '$$$', '', '', '%%%', '', '&&&'] : 10 : '###'
2 : ['###', '', '@@@', '', '$$$', '', '', '%%%', '', '&&&'] : 10 : ''
3 : ['###', '@@@', '', '$$$', '', '', '%%%', '', '&&&'] : 9 : ''
4 : ['###', '@@@', '$$$', '', '', '%%%', '', '&&&'] : 8 : ''
5 : ['###', '@@@', '$$$', '', '%%%', '', '&&&'] : 7 : '%%%'
6 : ['###', '@@@', '$$$', '', '%%%', '', '&&&'] : 7 : ''

注意:代码不能正常工作。这里有一些空字符串 输出。 后来我找到了更好的方法: 列表理解:[x for x in lst if x!=''] 或创建一个新列表并将非空字符串复制到它,这发生了 比上面的代码更有效,因为它不涉及转移 每次从列表中删除元素时的位置。

但是我对上面代码的输出有一些疑问。

第一个问题是,为什么循环不运行十次(迭代次数打开     因为列表的原始长度是十。     其次,如果你看最右边的列,你会发现它不会打印 打印@@@字符串。完全跳过它!我的理论是in运算符 是一个索引的糖(最有可能),所以即使列表的长度发生变化 指数继续增加一。这可以解释为什么在第三次迭代 由于i@@@lst[2]的值为空字符串,而不是''

使用in运算符时是否需要了解一些内容?

2 个答案:

答案 0 :(得分:2)

任何时候你在迭代过程中删除东西时都会得到奇怪的结果。如果迭代切片[:],字符串将不再消失

for item in lst[:]:

创建一个迭代的副本,以便您可以操作列表的元素而不影响迭代

this帖子描述了在迭代时修改列表时会发生什么。

答案 1 :(得分:0)

在内部,迭代列表使用索引。每次通过循环时,此索引递增1,并用于检索所需的元素。如果在迭代时删除一个元素,一个新元素将“移动到”你正在查看的插槽中,然后循环的下一个迭代将查看下一个,所以首先移动的元素永远不会被查看在

一些解决方案包括:

  • 创建一个新列表(可能使用列表推导),而不是从旧列表中删除项目。如果需要,可以使用切片分配将此新列表分配回原始容器:lst[:] = (item for item if item != "")这是最快的,因为它可以避免在删除时多次移动项目。
  • 使用reversed()以相反顺序迭代列表,这样您就只能“移动”您已经看过的项目。
  • 迭代列表的副本,但修改原始列表。

在您的情况下,您实际上不需要遍历列表。您只想从中删除空字符串。所以第四个选择是删除空字符串,直到没有更多!

try:
     while True:
         lst.remove('')   # deletes first empty string
except ValueError:        # no more empty strings
     pass