在Python中,我注意到如果我用
for x in y
迭代列表,并且在循环中删除
y
的元素,最后一个元素将被“跳过” - 我假设这是因为
len(y)
已更改。
我正在尝试获取具有特定扩展名的所有文件,但满足某些条件的文件除外。
这是原始代码:
def test_print_numTXTs(fileList):
counter = 0
for file in fileList:
if file.name[-4:] == ".txt":
counter +=1
if file.name == "a.txt":
fileList.remove(file) #problem caused here
print(counter)
print(len(fileList))
counter
的输出比总数少 1 .txt 文件。单步调试器,我可以看到它正在跳过循环的最后一次迭代(我假设因为
len(fileList)
现在是
-=1
w.r.t. 它的初始
len()
)。
以下代码“有效”,但感觉就像黑客一样 - 我将要从列表中删除的文件添加到第二个列表中,然后在事后迭代该文件。我已经注释掉了最初的行,这导致了迭代的“跳过”。
def print_numTXTs(fileList):
filesToRemoveFromList = []
counter = 0
for file in fileList:
if file.name[-4:] == ".txt":
counter +=1
if file.name == "a.txt":
#fileList.remove(file) #problem caused here
filesToRemoveFromList.append(file)
print(counter)
for file in filesToRemoveFromList:
fileList.remove(file)
print(len(fileList))
此代码输出所有 .txt 文件的计数,并且列表的长度比该长度少一(因为元素 a.txt 已被删除) - 这是所需的行为。
这个问题有更优雅的解决方案吗?
在迭代列表时不应该修改列表,因为这会导致观察到的意外行为。的第二种方法(创建要删除的项目列表,然后在一个单独的循环中删除它们)是一种可行的方法。但是,使用列表推导来构建新的过滤列表是一种更 Pythonic 和高效的方法。
这是可以如何执行此操作:
def print_numTXTs(fileList):
fileList = [file for file in fileList if file.name != "a.txt"]
counter = sum(1 for file in fileList if file.name.endswith(".txt"))
print(counter)
print(len(fileList))
此代码执行以下操作:
-
创建新列表:
它使用列表推导来创建一个新的
fileList
版本,其中排除了名称为“a.txt”的文件。[file for file in fileList if file.name != "a.txt"]
此部分检查每个file
,如果其名称不是a.txt
,则将其包含在新列表中。 - 计算 .txt 文件: 它使用生成器表达式有效地计算结果列表中扩展名为“.txt”的文件数。
-
打印结果:
它打印
.txt
文件的计数和更新后的fileList
的长度。
此方法更简洁、更高效,因为它避免了修改原始列表时的就地突变和潜在问题。
标签:python From: 67213415