tqdm:提取已用时间和剩余时间?

12

我一直在查看tqdm文档,但无论我看哪里,都找不到提取已用时间和估计剩余时间字段的方法(基本上是每行进度条的中心:00:00<00:02)。

 0%|          | 0/200 [00:00<?, ?it/s]
  4%|▎         | 7/200 [00:00<00:02, 68.64it/s]
  8%|▊         | 16/200 [00:00<00:02, 72.87it/s]
 12%|█▎        | 25/200 [00:00<00:02, 77.15it/s]
 17%|█▋        | 34/200 [00:00<00:02, 79.79it/s]
 22%|██▏       | 43/200 [00:00<00:01, 79.91it/s]
 26%|██▌       | 52/200 [00:00<00:01, 80.23it/s]
 30%|███       | 61/200 [00:00<00:01, 82.13it/s]
....
100%|██████████| 200/200 [00:02<00:00, 81.22it/s]

tqdm通过在每次更新时打印动态进度条来工作,但是否有一种方法可以“只”打印00:0100:02部分,以便我可以在Python程序的其他地方使用它们,例如自动停止代码,如果进程时间过长,则停止该过程?

4个回答

22
对象通过公共属性format_dict公开一些信息。
from tqdm import tqdm
    
# for i in tqdm(iterable):
with tqdm(iterable) as t:
    for i in t:
        ...
        elapsed = t.format_dict['elapsed']
        elapsed_str = t.format_interval(elapsed)

否则,您可以解析str(t).split()

tqdm中的format_dict可以获取elapsed,但是否有办法获取剩余时间呢? - glezo
我应该把循环放在哪里?如果放在内部(例如,如果循环没有移动而是停留在某处)。基本上,如何重写“for i in tqdm(range(100)):”,以便完成后可以访问经过的时间值(理想情况下还包括每秒迭代次数,但似乎不包括在format_dict中)? - stam

2
您可以从 format_dict 和一些计算中获取经过的时间剩余时间
t = tqdm(total=100)
...
elapsed = t.format_dict["elapsed"]
rate = t.format_dict["rate"]
remaining = (t.total - t.n) / rate if rate and t.total else 0  # Seconds*

1

这里是关于剩余时间和已过时间问题的答案:

from tqdm import tqdm
from time import sleep
    
with tqdm(total=100, bar_format="{l_bar}{bar} [ time left: {remaining}, time spent: {elapsed}]") as pbar:
        for i in loop:
            pbar.update(1)
            sleep(0.01)

如果需要在其他地方使用或打印:
elapsed = pbar.format_dict["elapsed"]
remains = pbar.format_dict["remaining"]

-2
编辑:请查看库维护者下面的回答。事实证明,可以在公共API中获取此信息。

tqdm并不在其公共API中公开该信息,我不建议尝试将其自己的信息添加到其中。那样你就会依赖于tqdm的实现细节,这些细节可能随时发生变化。

然而,这并不应该阻止你编写自己的代码。使用计时器来检测循环是非常容易的,如果循环时间过长,你可以中断它。下面是一个快速、粗略的示例,仍然使用tqdm提供视觉反馈:

import time
from tqdm import tqdm


def long_running_function(n, timeout=5):
    start_time = time.time()

    for _ in tqdm(list(range(n))):
        time.sleep(1)  # doing some expensive work...
        elapsed_time = time.time() - start_time
        if elapsed_time > timeout:
            raise TimeoutError("long_running_function took too long!")


long_running_function(100, timeout=10)

如果你运行这个函数,它将在10秒后通过抛出异常停止自己的执行。你可以在调用处捕获这个异常,并以任何你认为合适的方式做出响应。
如果你想变得聪明,甚至可以在像 tqdm 这样的包装器中将其分解出来,如下所示:
def timed_loop(iterator, timeout):
    start_time = time.time()
    iterator = iter(iterator)

    while True:
        elapsed_time = time.time() - start_time
        if elapsed_time > timeout:
            raise TimeoutError("long_running_function took too long!")

        try:
            yield next(iterator)
        except StopIteration:
            pass


def long_running_function(n, timeout=5):
    for _ in timed_loop(tqdm(list(range(n))), timeout=timeout):
        time.sleep(0.1)


long_running_function(100, timeout=5)

1
如果目前tqdm没有这种功能(这很令人惊讶),那么这仍然是一个验证的好答案。感谢您在手动实现tqdm时提供的所有代码,这使我想到了自己还没有想到的时间检查方法。 - Coolio2654
2
这是错误的答案。@casper.dcl 给出了正确的答案,即作者/维护者。 - nurettin
1
为什么一个明显错误的答案被接受,而正确和官方的回答却没有被接受?难道楼主不知道可以更改已接受的答案吗?无论如何,这似乎对公众有好处。 - Vainmonde De Courtenay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接