在尝试删除所有不以列表中的特定子字符串开头的文件名时,我遇到了以下意外行为:
>>> 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}}基本上只是一个别名。
答案 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])