list.remove()方法未提供预期结果

时间:2012-01-05 15:33:59

标签: python list

在尝试删除所有不以列表中的特定子字符串开头的文件名时,我遇到了以下意外行为:

>>> allfiles = os.listdir(mydir)
>>> allfiles
['dwcpybyext.sh', 'dwlaunch', 'libupdate.sh', 'ntpsync.sh']
>>> for f in allfiles:
...    if f.startswith('n') == False:
...        allfiles.remove(f)
...
>>> allfiles
['dwlaunch', 'ntpsync.sh']

理论上应该从列表中删除不以'n'开头的每个文件名。相反,它在列表中以'd'开头。如果我更改循环以使用if f.startswith('d') == False:我得到['dwcpybyext.sh', 'dwlaunch', 'ntpsync.sh'] - 最后一项甚至不包含'd'字符。

为什么我会看到这种行为?似乎不太可能是Python的list.remove()方法中的错误 - 如果我替换del allfiles[allfiles.index(f)],我会得到相同的行为,{无论如何,{1}}基本上只是一个别名。

4 个答案:

答案 0 :(得分:7)

在迭代时修改列表是一个非常糟糕的主意。尝试下一个:

allfiles = filter(lambda x: x.startswith('n'), allfiles)

答案 1 :(得分:2)

你不应该改变你正在迭代的列表。使用

allfiles = [f for f in allfiles if f.startswith('n')]

代替。

更新:@RomanBodnarchuk与filter替代品的小型效果比较(当然,这完全没问题):

$ python -mtimeit -s'L=range(10000)' '[x for x in L if x < 100]'
1000 loops, best of 3: 662 usec per loop
$ python -mtimeit -s'L=range(10000)' 'filter(lambda x: x < 100, L)'
100 loops, best of 3: 2.06 msec per loop

似乎列表推导比filter lambda快3倍。

答案 2 :(得分:1)

不确切地知道,但可能与你正在修改你正在迭代的列表的事实有关!不要那样做。相反,使用这样的代码:

allfiles = [f for f in os.listdir(mydir) if f.startswith('n')

或者,如果您更喜欢循环:

allfiles = []
for f in os.listdir(mydir):
    if f.startswith('n'):
        allfiles.append(f)

答案 3 :(得分:0)

您正在修改您正在迭代的相同列表。

您必须复制列表或以相反的顺序迭代它并使用索引访问列表,以便以前的索引始终存在

example = ['a','b','c']
for i in reversed(range(len(example))):
    if example[i] == 'b':
        del(example[i])