Python进度条

548

当我的脚本执行一些可能需要时间的任务时,如何使用进度条呢?

例如,在完成某个函数并返回True时需要一定的时间。我如何在函数执行期间显示进度条呢?

请注意,我需要实时显示进度条,所以我不知道该怎么办。我需要为此使用thread吗?我不知道。

目前我在函数执行期间没有任何打印输出,但一个进度条会很好。我更关心的是从代码角度如何实现这一点。


你是使用GUI工具包还是仅限于CLI? - Bobby
使用GUI可以做到这一点,但我对CLI部分感兴趣。无论如何,我可以使用第三方库。 - user225312
4
可能是重复的问题,与“在控制台中的文本进度条”有关。请注意,虽然这个问题发布时间早于另一个问题三天,但是链接的那个问题更常被查看。 - Greenstick
这是一个在Jupyter Notebook中的解决方案:https://mikulskibartosz.name/how-to-display-a-progress-bar-in-jupyter-notebook-47bd4c2944bf - Steven C. Howell
我发布了一种新型进度条,你可以打印它,查看吞吐量和预计时间,甚至可以暂停它,除此之外还有非常酷的动画效果!请查看:https://github.com/rsalmei/alive-progress alive-progress - rsalmei
我没有循环,只有一个写入命令。在这种情况下,是否可能?with open(path2file, 'wb+') as f: # with open(path2file, 'w+') as f: f.write(data.read()) - Charlie Parker
47个回答

1
尝试使用PyProg。PyProg是一个开源库,用于Python创建高度可定制的进度指示器和进度条。
它目前的版本是1.0.2;它托管在Github上,并可在PyPI上获取(下面有链接)。它与Python 3和2兼容,也可以与Qt控制台一起使用。
使用它非常简单。以下代码:
import pyprog
from time import sleep

# Create Object
prog = pyprog.ProgressBar(" ", "", 34)
# Update Progress Bar
prog.update()

for i in range(34):
    # Do something
    sleep(0.1)
    # Set current status
    prog.set_stat(i + 1)
    # Update Progress Bar again
    prog.update()

# Make the Progress Bar final
prog.end()

将产生:

Initial State:
Progress: 0% --------------------------------------------------

When half done:
Progress: 50% #########################-------------------------

Final State:
Progress: 100% ##################################################

我实际上创建了PyProg,因为我需要一个简单但超级可定制的进度条库。您可以轻松安装它: pip install pyprog
PyProg Github: https://github.com/Bill13579/pyprog
PyPI: https://pypi.python.org/pypi/pyprog/

1

以下是对jelde015(当然要感谢他)的更通用的回答:

如果需要手动更新加载条,则可以使用以下方法:

import sys
from math import *


def loadingBar(i, N, size):
    percent = float(i) / float(N)
    sys.stdout.write("\r"
                     + str(int(i)).rjust(3, '0')
                     +"/"
                     +str(int(N)).rjust(3, '0')
                     + ' ['
                     + '='*ceil(percent*size)
                     + ' '*floor((1-percent)*size)
                     + ']')

并通过以下方式调用它:
loadingBar(7, 220, 40)

将产生以下结果:
007/220 [=                                       ]  

只需使用当前的i值随时调用它。

size设置为进度条应该包含的字符数。


1

我使用wget,但是你需要在Windows的命令提示符或Mac或Linux上的终端中安装该模块。

pip install wget

很简单,只需要使用download()函数即可。

import wget
url = input("Enter Url to download: ")
wget.download(url)

tqdm也是一个选项,您也需要下载该模块。

pip install tqdm

现在确保导入模块,设置范围并传递参数。

from tqdm import tqdm
for i in tqdm(range(int(9e7))):
    pass

这也非常好! - ChesterWOV

1

已经有很多好的答案了,但是基于@HandyGold75的回答,我想让它在特定的上下文中可调用,以及在结尾处提供以秒为单位的时间反馈。

from time import sleep, time


class ProgressBar:
    def __init__(self, total: float, width: int = 50, msg: str = ""):
    self.total = total
    self.width = width
    self.start: float = time()
    if msg:
        print(f"{msg}")

    def progress(self, progress: float):
        percent = self.width * ((progress) / self.total)
        bar = chr(9608) * int(percent) + "-" * (self.width - int(percent))
        print(
            f"\r|{bar}| {(100/self.width)*percent:.2f}% "
            f"[{progress} of {self.total}]",
            end="\r",
        )

    def __enter__(self):
        return self.progress

    def __exit__(self, type, value, traceback):
        end: float = time()
        print(f"\nFinished after {end - self.start: .3f} seconds.")


# USAGE
total_loops = 150
with ProgressBar(total=total_loops) as progress:
    for i in range(total_loops):
        sleep(0.01)  # Do something usefull here
        progress(i + 1)

0
#doesnt affect actual execution
#based on events and consumption in background
#may be that actual process completes a bit earlier than progress shows 99%
#make an instance with number of elements in a loop
#in each iteration call the method current_progress

import time
from math import ceil
import os
import sys
from threading import Thread
class progress_bar(object):
 def __init__(self,total_elements,length_bar=25):
  self.length_bar=length_bar
  self.total_elements=total_elements
  self.singleweight=(float(1)/float(total_elements))*100
  self.done=0
  self.qt=[0]
  self.call_count=0
  t=Thread(target=self.display_progress)
  t.start()
 def current_progress(self):
  self.done+=1
  self.qt=[self.done]+self.qt
 def display_progress(self):
  while True:
   try:
    done=self.qt.pop()
   except:
    continue
   else:
    self.call_count+=1
    self.progress=self.singleweight*done
    fill=ceil(self.progress)
    bar=int((fill*self.length_bar)/100)*"|"
    bar="["+bar+str(fill)+"%"
    barp=bar
    for i in range(0,self.length_bar+3-(len(bar))):
     barp=barp+"_"
    barp=barp+"]"
    if self.progress <= 100:
     os.system("clear")
     print("Progress:",barp, sep=' ', end='\n', file=sys.stdout, flush=True)
    if self.call_count == self.total_elements:
     break
  else:
   pass

0
受到许多没有包依赖的答案的启发,我在这里分享我的实现。在任何循环中使用的函数需要当前迭代次数、总迭代次数和初始时间。
import time    
def simple_progress_bar(i: int, n: int, init_time: float):
    avg_time = (time.time()-init_time)/(i+1)
    percent = ((i+1)/(n))*100
    print(
        end=f"\r|{'='*(int(percent))+'>'+'.'*int(100-int(percent))}|| " + \
        f"||Completion: {percent : 4.3f}% || \t "+ \
        f"||Time elapsed: {avg_time*(i+1):4.3f} seconds || \t " + \
        f"||Remaining time: {(avg_time*(n-(i+1))): 4.3f} seconds."
    )
    return



N = 325
t0 = time.time()
for k in range(N):
    # stuff goes here #
    time.sleep(0.0001)
    # stuff goes here #
    
    simple_progress_bar(k, N, t0)

0

您可以使用丰富的库,其中包括非常好的终端样式,包括进度条。 首先运行以下命令: pip install rich

文档示例:

import time
from rich.progress import track

for i in track(range(20), description="Processing..."):
    time.sleep(1)  # Simulate work being done

0

iterrows的进度条。适应@eusoubrasileiro代码,用于在循环遍历数据框行时显示进度。此外还显示百分比、ith/count、经过的秒数、每秒迭代次数和剩余秒数。允许指定第n个更新计数(每个)。

import time
import sys
def progressbar_iterrows(df, prefix="", size=60, file=sys.stdout, per=1000):
    count = len(df)
    t = 0
    def show(j,elapsed):
        avg = 0 if elapsed == 0 else j/elapsed
        remaining = 0 if avg == 0 else (count-j)/avg
        x = int(size*j/count)
        file.write("%s[%s%s] %i%% %i/%i elapsed:%i %i/sec remaining:%i\r" % (prefix, "#"*x, "."*(size-x), j/count, j, count, elapsed, avg, remaining))
        file.flush()
    file.write("Initializing ...\r")
    file.flush()
    for i, item in df.iterrows():
        yield i,item
        if t == 0:
            t = time.time()
        if i % per == 0:
            show(i,time.time()-t)
    file.write("\n")
    file.flush()

使用方法:

    for n,r in progressbar_iterrows(br_b_sections_df, "Processed: "):
        # do something

输出:

Processed: [........................] 0% 5000/28751240 elapsed:12 413/sec remaining:55054

0

@Massagran:它在我的程序中工作良好。此外,我们需要添加一个计数器来指示循环次数。该计数器作为方法update的参数。 例如:读取测试文件的所有行并对其进行某些处理。假设函数dosth()不涉及变量i

lines = open(sys.argv[1]).readlines()
i = 0
widgets=[Percentage(), Bar()]
pbar = ProgressBar(widgets=widgets,maxval=len(lines)).start()
pbar.start()
for line in lines:<pre>
    dosth();
    i += 1
    pbar.update(i)</pre>
pbar.finish()

变量i通过方法update控制pbar的状态。

0
你应该将进度条与正在进行的任务连接起来(这样它就可以测量进度 :D)。例如,如果你正在进行 FTP 文件传输,你可以告诉 ftplib 抓取一定大小的缓冲区,比如说 128K,然后在你的进度条上添加文件大小 128k 所代表的百分比。如果你正在使用 CLI,并且你的进度条有 20 个字符长,那么当文件传输了 1/20 的部分时,你应该添加一个字符进去。

在我的情况下,我正在使用一个API,它不提供获取特定块的功能。不过还是谢谢你的想法,很好。 - user225312

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