首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在函数内的for循环上使用tqdm检查进度

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

Stack Overflow用户
提问于 2016-03-13 19:04:12
回答 6查看 17.4K关注 0票数 6

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

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

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

代码语言:javascript
复制
for dirPath, subdirList, fileList in tqdm(os.walk(target_dir)):
        sleep(0.01)
        dirName = dirPath.split(os.path.sep)[-1]
        for fname in fileList:
        *****

输出:

代码语言:javascript
复制
Scanning Directory....
43it [00:23, 11.24 it/s]

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

EN

回答 6

Stack Overflow用户

发布于 2016-03-13 19:26:32

你不能显示完成的百分比,除非你知道“完成”是什么意思。

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

如果您决意要显示进度条,那么可以将数据放入内存中的列表中:list(os.walk(target_dir))。我不推荐这样做。如果你正在遍历一个大的目录树,这可能会消耗大量内存。更糟糕的是,如果followlinksTrue,并且您有一个循环的目录结构(子目录链接到其父目录),那么它可能会一直循环下去,直到内存耗尽。

票数 7
EN

Stack Overflow用户

发布于 2016-05-15 09:34:11

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

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

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

代码语言:javascript
复制
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包装器的情况下获得相同的结果,但它会稍微复杂一些,因为您必须在遍历每个子文件夹之后恢复最后一个进度条状态:

代码语言:javascript
复制
# 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)
票数 3
EN

Stack Overflow用户

发布于 2016-03-13 19:25:08

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

代码语言:javascript
复制
for dirPath, subdirList, fileList in tqdm(list(os.walk(target_dir))):

来自tdqm模块的文档:

如果可能的话,使用

len(可迭代)。作为最后的手段,只显示基本的进度统计信息(没有ETA,没有进度条)。

但是,len(os.walk(target_dir))是不可能的,所以没有预计时间或进度条。

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35969433

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档