为什么tqdm打印到新一行而不是更新同一行?

149

我正在使用Python编写一个小型命令行游戏,使用tqdm模块显示进度条。我使用msvcrt模块监听用户输入,以中断进度。一旦被中断,用户可以通过在命令行提示符中输入“restart”来重新开始。第二次显示进度条时,不会更新同一行的进度,而是每次创建一个新行。

如何将其显示在同一行上?

Progress bar issue

这段代码片段说明了我对进度条的使用。

def transfer():
    for i in tqdm.tqdm(range(1000), desc="Transfer progress", ncols=100, bar_format='{l_bar}{bar}|'):
        sleep(.1)
        if msvcrt.kbhit():
            if msvcrt.getwche() == ' ':
                interrupt()
                break

def interrupt():
    type("File transfer interrupted, to restart the transfer, type 'restart'")

3
好的,以下是您需要翻译的内容:https://github.com/tqdm/tqdm/issues/375 - sirex
1
https://github.com/tqdm/tqdm/issues/313 - user
3
有没有一个地方可以解释为什么会发生这种情况? - Eduardo Reis
19个回答

3

我遇到的问题可能不常见,但如果有用的话,我在控制台打印了另一个变量。禁用该打印功能可以解决问题。


1
这是关键!如果你有任何打印语句,它会搞乱事情。 - user3180

3

导入tqdm库。

from tqdm import tqdm

首先,在使用 tqdm 的代码中启动它,但由于多行输出而停止。

然后执行以下操作:

list(getattr(tqdm, '_instances'))

for instance in list(tqdm._instances):
    tqdm._decr_instances(instance)

如果您遇到以下错误:

AttributeError: type object 'tqdm' has no attribute '_instances'

您需要先启动使用了 tqdm 的代码,然后再启动提到它的其他代码。

在进行所有这些操作之后,您的 tqdm 将正常工作。


3
以下方法有些取巧,但似乎可以很好地重置tqdm:

最初的回答:
from tqdm import tqdm as tqdm_base
def tqdm(*args, **kwargs):
    if hasattr(tqdm_base, '_instances'):
        for instance in list(tqdm_base._instances):
            tqdm_base._decr_instances(instance)
    return tqdm_base(*args, **kwargs)

有时在开始时会打印出以前的输出(我不确定如何删除),但我觉得这比换行符要少得多(特别是在长循环中)。"最初的回答"

这个非常好用,谢谢。 - Cerberton

2

leave=False 在我的情况下适用于内部循环。

for j in tqdm(outer_list):
    for i in tqdm(inner_list, leave=False):

环境为tqdm==4.38.0Python 3.6.7


在终端中也适用于多个循环,但在笔记本中不适用(它们都保持原位)。 - KSHMR

1
尽管原始问题似乎是针对Linux shell的。但是从Windows命令行来看,以下方法有效。
from tqdm import tqdm

for x in tqdm([1,2,3,4], leave=True, ncols=80, position=0):
    pass
    for y in tqdm([1,2,3,4], leave=False, ncols=80, position=1):
        pass

我觉得如果我阅读了文档,而不是盲目尝试所有建议的修复方法,我会更快地解决这个问题!


0

0

尝试使用 tqdm.tnrange()

for i in tqdm.tnrange(len(df)):

Ongoing image finished image


3
请将代码作为代码块包含,而不是作为图片,这样更容易复制/粘贴(同时也可以减少 Stack Overflow 的托管成本)。 - Nino Filiu
1
啊抱歉,但是这段代码只有 for i in tqdm.tnrange(len(df)): 其余的是为 Jupyter 设计的,因为在笔记本内也会发生换行打印。 - ASHu2

0

我尝试了tqdm的解决方案,但由于我使用Spyder(Anaconda),在其他答案中提到的写入和打印命令之间的冲突,它在我的情况下不起作用。我想出了一个简单而有效的解决方案,虽然不是最花哨的。

def ybar(progr, total, step=50):
    #starts with 1
    l2=(progr/total)//(1/step)
    if progr==1: print(f'[{total}]: '+'|'*int(l2), end = '') 
    else:
        l1=((progr-1)/total)//(1/step) 

        ll=int(l2-l1)
        if l1 < l2: 

            for j in range(1,ll+1):
                if (int(l1)+j)%5==0:
                    print('*', end = '')
                else:
                    print('|', end = '')
        if progr==total: print("  DONE")

作为结果,您将得到简单的:[100]:||||||

for i in range(1,101):
    ybar(i,len(range(1,101)),50)
    #something

这里有很多解决方案:Python 进度条

-8

尝试使用from tqdm import tqdm_notebook as tqdm代替from tqdm import tqdm


1
真的吗?那只适用于jupyter/ipython笔记本,而在这里似乎并不适用。 - Winston Ewert

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