在函数内部的for循环上使用tqdm检查进度

2024-06-16 08:43:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用for循环遍历目录树中的一个大型组文件。

在执行此操作时,我希望通过控制台中的进度条监视进度。所以,我决定使用tqdm来实现这个目的。

目前,我的代码如下所示:

for dirPath, subdirList, fileList in tqdm(os.walk(target_dir)):
        sleep(0.01)
        dirName = dirPath.split(os.path.sep)[-1]
        for fname in fileList:
        *****

输出:

Scanning Directory....
43it [00:23, 11.24 it/s]

所以,我的问题是它没有显示进度条。我想知道如何正确使用它,并更好地了解它的工作原理。此外,如果有任何其他替代品的全面质量管理,可以在这里使用。


Tags: 文件代码进度条in目的目录targetfor
3条回答

除非您知道“complete”是什么意思,否则您不能显示percentage complete

os.walk正在运行时,它不知道最终将迭代多少个文件和文件夹:返回类型os.walk没有__len__。它必须从目录树的一路往下看,枚举所有的文件和文件夹,以便对它们进行计数。换句话说,os.walk必须做两次所有的工作,才能告诉您它将生产多少个项目,这是低效的。

如果在显示进度条时已经死机,则可以将数据假脱机到内存列表中:list(os.walk(target_dir))。我不推荐这个。如果你正在遍历一个大目录树,这可能会消耗大量内存。更糟糕的是,如果followlinksTrue,并且您有一个循环目录结构(子目录链接到其父目录),那么它可能永远循环,直到您用完RAM。

因为tqdm不知道os.walk的结果会有多长,因为它是一个生成器,所以不能对它调用len。您可以首先将os.walk(target_dir)转换为列表来解决此问题:

for dirPath, subdirList, fileList in tqdm(list(os.walk(target_dir))):

tdqm模块的文档中:

len(iterable) is used if possible. As a last resort, only basic progress statistics are displayed (no ETA, no progressbar).

但是,len(os.walk(target_dir))是不可能的,因此没有ETA或进度条。

正如本杰明所指出的,使用list确实会占用一些内存,但不会占用太多内存。一个包含约190000个文件的假脱机目录导致Python在我的Windows 10计算机上使用了大约65MB的内存。

作为explained in the documentation,这是因为您需要提供进度指示器。根据对文件所做的操作,可以使用文件计数或文件大小。

其他答案建议将os.walk()生成器转换为列表,以便获得__len__属性。但是,这将消耗大量内存,具体取决于您拥有的文件总数。

另一种可能是预计算:首先遍历整个文件树并计算文件总数(但不保留文件列表,只保留计数!),然后您可以再次漫游,并为tqdm提供预计算的文件计数:

def walkdir(folder):
    """Walk through every files in a directory"""
    for dirpath, dirs, files in os.walk(folder):
        for filename in files:
            yield os.path.abspath(os.path.join(dirpath, filename))

# Precomputing files count
filescount = 0
for _ in tqdm(walkdir(target_dir)):
    filescount += 1

# Computing for real
for filepath in tqdm(walkdir(target_dir), total=filescount):
        sleep(0.01)
        # etc...

注意,我在os.walkdir上定义了一个包装函数:因为您是在处理文件而不是目录,所以最好定义一个在文件而不是目录上进行的函数。

但是,您可以在不使用walkdir包装器的情况下获得相同的结果,但这会有点复杂,因为您必须在遍历每个子文件夹之后恢复上一个进度条状态:

# Precomputing
filescount = 0
for dirPath, subdirList, fileList in tqdm(os.walk(target_dir)):
    filescount += len(filesList)

# Computing for real
last_state = 0
for dirPath, subdirList, fileList in os.walk(target_dir):
    sleep(0.01)
    dirName = dirPath.split(os.path.sep)[-1]
    for fname in tqdm(fileList, total=filescount, initial=last_state):
        # do whatever you want here...
    # Update last state to resume the progress bar
    last_state += len(fileList)

相关问题 更多 >