Python Progress Bar
当我的脚本执行可能需要一些时间的任务时,如何使用进度条?
例如,一个需要一些时间才能完成的函数,并在完成时返回
请注意,我需要实时,所以我无法弄清楚该怎么做。 我需要一个
现在我正在执行函数时不打印任何内容,但是进度条会很好。 此外,我更感兴趣的是从代码的角度来看如何做到这一点。
使用tqdm,您可以在一秒钟内为循环添加进度表:
1 2 3 4 5 6 7 8 | In [1]: import time In [2]: from tqdm import tqdm In [3]: for i in tqdm(range(10)): ....: time.sleep(3) 60%|██████ | 6/10 [00:18<00:12, 0.33 it/s] |
此外,还有一个tqdm的图形版本,因为
1 2 3 4 5 6 | In [1]: import time In [2]: from tqdm import tqdm_gui In [3]: for i in tqdm_gui(range(100)): ....: time.sleep(3) |
但要小心,因为
有特定的库(像这里这样)但也许很简单的事情会做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import time import sys toolbar_width = 40 # setup toolbar sys.stdout.write("[%s]" % ("" * toolbar_width)) sys.stdout.flush() sys.stdout.write("\b" * (toolbar_width+1)) # return to start of line, after '[' for i in xrange(toolbar_width): time.sleep(0.1) # do real work here # update the bar sys.stdout.write("-") sys.stdout.flush() sys.stdout.write("] ") # this ends the progress bar |
注意:progressbar2是一个进度条的分支,几年没有维护。
以上建议非常好,但我认为大多数人只是想要一个现成的解决方案,不依赖于外部包,但也可以重用。
我得到了上述所有内容的最佳分数,并将其作为一个函数,以及一个测试用例。
要使用它,只需复制"def update_progress(progress)"下的行,但不要复制测试脚本。不要忘记导入sys。只要您需要显示或更新进度条,请调用此方法。
这通过直接将" r"符号发送到控制台以将光标移回开始来工作。 python中的"print"没有为此目的识别上述符号,因此我们需要'sys'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | import time, sys # update_progress() : Displays or updates a console progress bar ## Accepts a float between 0 and 1. Any int will be converted to a float. ## A value under 0 represents a 'halt'. ## A value at 1 or bigger represents 100% def update_progress(progress): barLength = 10 # Modify this to change the length of the progress bar status ="" if isinstance(progress, int): progress = float(progress) if not isinstance(progress, float): progress = 0 status ="error: progress var must be float " if progress < 0: progress = 0 status ="Halt... " if progress >= 1: progress = 1 status ="Done... " block = int(round(barLength*progress)) text =" Percent: [{0}] {1}% {2}".format("#"*block +"-"*(barLength-block), progress*100, status) sys.stdout.write(text) sys.stdout.flush() # update_progress test script print"progress : 'hello'" update_progress("hello") time.sleep(1) print"progress : 3" update_progress(3) time.sleep(1) print"progress : [23]" update_progress([23]) time.sleep(1) print"" print"progress : -10" update_progress(-10) time.sleep(2) print"" print"progress : 10" update_progress(10) time.sleep(2) print"" print"progress : 0->1" for i in range(100): time.sleep(0.1) update_progress(i/100.0) print"" print"Test completed" time.sleep(10) |
这是测试脚本显示的结果(最后一个进度条动画):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | progress : 'hello' Percent: [----------] 0% error: progress var must be float progress : 3 Percent: [##########] 100% Done... progress : [23] Percent: [----------] 0% error: progress var must be float progress : -10 Percent: [----------] 0% Halt... progress : 10 Percent: [##########] 100% Done... progress : 0->1 Percent: [##########] 99.0% Test completed |
这个答案不依赖于外部包,我也认为大多数人只想要一个现成的代码。下面的代码可以通过自定义来调整以适应您的需要:条形进度符号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import sys def progressbar(it, prefix="", size=60, file=sys.stdout): count = len(it) def show(j): x = int(size*j/count) file.write("%s[%s%s] %i/%i " % (prefix,"#"*x,"."*(size-x), j, count)) file.flush() show(0) for i, item in enumerate(it): yield item show(i+1) file.write(" ") file.flush() |
用法:
1 2 3 4 | import time for i in progressbar(range(15),"Computing:", 40): time.sleep(0.1) # any calculation you need |
输出:
1 | Computing: [################........................] 4/15 |
-
不需要第二个线程。上面的一些解决方案/包需要。例如,对于
jupyter notebook ,第二个线程可能是个问题。 -
与任何迭代一起使用它意味着可以使用
len() 的任何东西。例如['a', 'b', 'c' ... 'g'] 的list ,dict
您也可以通过将文件更改为
对于类似的应用程序(跟踪循环中的进度)我只是使用python-progressbar:
他们的例子是这样的,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from progressbar import * # just a simple progress bar widgets = ['Test: ', Percentage(), ' ', Bar(marker='0',left='[',right=']'), ' ', ETA(), ' ', FileTransferSpeed()] #see docs for other options pbar = ProgressBar(widgets=widgets, maxval=500) pbar.start() for i in range(100,500+1,50): # here do something long at each iteration pbar.update(i) #this adds a little symbol at each iteration pbar.finish() |
在搜索了等效的解决方案之后,我刚刚为我的需求做了一个简单的进度课程。我以为我可能会发布它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | from __future__ import print_function import sys import re class ProgressBar(object): DEFAULT = 'Progress: %(bar)s %(percent)3d%%' FULL = '%(bar)s %(current)d/%(total)d (%(percent)3d%%) %(remaining)d to go' def __init__(self, total, width=40, fmt=DEFAULT, symbol='=', output=sys.stderr): assert len(symbol) == 1 self.total = total self.width = width self.symbol = symbol self.output = output self.fmt = re.sub(r'(?P<name>%\(.+?\))d', r'\g<name>%dd' % len(str(total)), fmt) self.current = 0 def __call__(self): percent = self.current / float(self.total) size = int(self.width * percent) remaining = self.total - self.current bar = '[' + self.symbol * size + ' ' * (self.width - size) + ']' args = { 'total': self.total, 'bar': bar, 'current': self.current, 'percent': percent * 100, 'remaining': remaining } print(' ' + self.fmt % args, file=self.output, end='') def done(self): self.current = self.total self() print('', file=self.output) |
示例:
1 2 3 4 5 6 7 8 9 | from time import sleep progress = ProgressBar(80, fmt=ProgressBar.FULL) for x in xrange(progress.total): progress.current += 1 progress() sleep(0.1) progress.done() |
将打印以下内容:
从https://pypi.python.org/pypi/progress尝试进度。
1 2 3 4 5 6 7 | from progress.bar import Bar bar = Bar('Processing', max=20) for i in range(20): # Do some work bar.next() bar.finish() |
结果将是如下栏:
1 | Processing |############# | 42/100 |
我喜欢Brian Khuu的简单而不需要外部包装的答案。我改了一下所以我在这里添加我的版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import sys import time def updt(total, progress): """ Displays or updates a console progress bar. Original source: https://stackoverflow.com/a/15860757/1391441 """ barLength, status = 20,"" progress = float(progress) / float(total) if progress >= 1.: progress, status = 1," " block = int(round(barLength * progress)) text =" [{}] {:.0f}% {}".format( "#" * block +"-" * (barLength - block), round(progress * 100, 0), status) sys.stdout.write(text) sys.stdout.flush() runs = 300 for run_num in range(runs): time.sleep(.1) updt(runs, run_num + 1) |
假设
1 | [#####---------------] 27% |
我非常喜欢python-progressbar,因为它非常简单易用。
对于最简单的情况,它只是:
1 2 3 4 5 6 | import progressbar import time progress = progressbar.ProgressBar() for i in progress(range(80)): time.sleep(0.01) |
外观可以定制,它可以显示估计的剩余时间。例如,使用与上面相同的代码,但是:
1 2 3 | progress = progressbar.ProgressBar(widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage(), ' ', progressbar.ETA()]) |
你可以使用tqdm:
1 2 3 4 5 6 | from tqdm import tqdm with tqdm(total=100, desc="Adding Users", bar_format="{l_bar}{bar} [ time left: {remaining} ]") as pbar: for i in range(100): time.sleep(3) pbar.update(1) |
在此示例中,进度条运行5分钟
它显示如下:
1 | Adding Users: 3%|█████▊ [ time left: 04:51 ] |
您可以根据需要进行更改和自定义。
如果它是一个具有固定迭代次数的大循环,需要花费很多时间才能使用我所做的这个函数。循环的每次迭代都会增加进度。其中count是循环的当前迭代,total是你循环到的值,size(int)是你想要的增量为10的大小,即(大小1 = 10个字符,大小2 = 20个字符)
1 2 3 4 5 | import sys def loadingBar(count,total,size): percent = float(count)/float(total)*100 sys.stdout.write(" " + str(int(count)).rjust(3,'0')+"/"+str(int(total)).rjust(3,'0') + ' [' + '='*int(percent/10)*size + ' '*(10-int(percent/10))*size + ']') |
例:
1 2 3 | for i in range(0,100): loadingBar(i,100,2) #do some code |
输出:
1 2 | i = 50 >> 050/100 [========== ] |
下面的代码是一个非常通用的解决方案,还有一个时间和剩余时间估计。你可以使用任何iterable。进度条的固定大小为25个字符,但它可以使用完整,半个和四分之一块字符以1%的步长显示更新。输出如下所示:
1 | 18% |████ | [0:00:01, 0:00:07] |
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import sys, time from numpy import linspace def ProgressBar(iterObj, refreshTime=10): #refreshTime=10: refresh the time estimate at least every 10 sec. def SecToStr(sec): m, s = divmod(sec, 60) h, m = divmod(m, 60) return u'%d:%02d:%02d'%(h,m,s) L = len(iterObj) steps = {int(x):y for x,y in zip(np.linspace(0,L, min(100,L),endpoint=False), np.linspace(0,100,min(100,L),endpoint=False))} qSteps = ['', u'\u258E',u'\u258C',u'\u258A'] # quarter and half block chars startT = endT = time.time() timeStr = ' [0:00:00, -:--:--]' for nn,item in enumerate(iterObj): if nn in steps: done = u'\u2588'*int(steps[nn]/4.0)+qSteps[int(steps[nn]%4)] todo = ' '*(25-len(done)) barStr = u'%4d%% |%s%s|'%(steps[nn], done, todo) if nn>0: endT = time.time() timeStr = ' [%s, %s]'%(SecToStr(endT-startT), SecToStr((endT-startT)*(L/float(nn)-1))) sys.stdout.write(' '+barStr+timeStr); sys.stdout.flush() elif time.time()-endT > refreshTime: endT = time.time() timeStr = ' [%s, %s]'%(SecToStr(endT-startT), SecToStr((endT-startT)*(L/float(nn)-1))) sys.stdout.write(' '+barStr+timeStr); sys.stdout.flush() yield item barStr = u'%4d%% |%s|'%(100, u'\u2588'*25) timeStr = ' [%s, 0:00:00] '%(SecToStr(time.time()-startT)) sys.stdout.write(' '+barStr+timeStr); sys.stdout.flush() # Example s = '' for op in ProgressBar(list('Disassemble and reassemble this string')): time.sleep(0.5) s += op print s |
欢迎提出改进建议或其他意见。
玩得开心。
使用此库:
用法:
1 2 3 4 | >>> import fish >>> while churning: ... churn_churn() ... fish.animate() |
玩得开心!
在Python3中它非常简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import time import math def show_progress_bar(bar_length, completed, total): bar_length_unit_value = (total / bar_length) completed_bar_part = math.ceil(completed / bar_length_unit_value) progress ="*" * completed_bar_part remaining ="" * (bar_length - completed_bar_part) percent_done ="%.2f" % ((completed / total) * 100) print(f'[{progress}{remaining}] {percent_done}%', end=' ') bar_length = 30 total = 100 for i in range(0, total + 1): show_progress_bar(bar_length, i, total) time.sleep(0.1) print(' ') |
在jupyter笔记本中运行时,使用普通tqdm不起作用,因为它在多行上写入输出。请改用:
1 2 3 4 5 | import time from tqdm import tqdm_notebook as tqdm for i in tqdm(range(100)) time.sleep(0.5) |
我喜欢这个页面。
从简单示例开始,然后转到多线程版本。开箱即用。不需要第三方包裹。
代码看起来像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import time import sys def do_task(): time.sleep(1) def example_1(n): for i in range(n): do_task() print '\b.', sys.stdout.flush() print ' Done!' print 'Starting ', example_1(10) |
或者这里是使用线程的示例,以便在程序运行时运行旋转加载栏:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import sys import time import threading class progress_bar_loading(threading.Thread): def run(self): global stop global kill print 'Loading.... ', sys.stdout.flush() i = 0 while stop != True: if (i%4) == 0: sys.stdout.write('\b/') elif (i%4) == 1: sys.stdout.write('\b-') elif (i%4) == 2: sys.stdout.write('\b\') elif (i%4) == 3: sys.stdout.write('\b|') sys.stdout.flush() time.sleep(0.2) i+=1 if kill == True: print '\b\b\b\b ABORT!', else: print '\b\b done!', kill = False stop = False p = progress_bar_loading() p.start() try: #anything you want to run. time.sleep(1) stop = True except KeyboardInterrupt or EOFError: kill = True stop = True |
你也可以使用enlighten。主要优点是您可以在不覆盖进度条的情况下同时登录。
1 2 3 4 5 6 7 8 9 10 | import time import enlighten manager = enlighten.Manager() pbar = manager.counter(total=100) for num in range(1, 101): time.sleep(0.05) print('Step %d complete' % num) pbar.update() |
它还处理多个进度条。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import time import enlighten manager = enlighten.Manager() odds = manager.counter(total=50) evens = manager.counter(total=50) for num in range(1, 101): time.sleep(0.05) if num % 2: odds.update() else: evens.update() |
这是一个以编程方式构建加载栏的简短解决方案(您必须决定需要多长时间)。
1 2 3 4 5 6 7 8 9 10 11 12 | import time n = 33 # or however many loading slots you want to have load = 0.01 # artificial loading time! loading = '.' * n # for strings, * is the repeat operator for i in range(n+1): # this loop replaces each dot with a hash! print(' %s Loading at %3d percent!' % (loading, i*100/n), end='') loading = loading[:i] + '#' + loading[i+1:] time.sleep(load) |
我喜欢加布里埃尔的答案,但我改变它是灵活的。您可以向该功能发送条形长度,并获得您想要的任何长度的进度条。并且您不能拥有零或负长度的进度条。此外,您可以像Gabriel一样使用此功能(请查看示例#2)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | import sys import time def ProgressBar(Total, Progress, BarLength=20, ProgressIcon="#", BarIcon="-"): try: # You can't have a progress bar with zero or negative length. if BarLength <1: BarLength = 20 # Use status variable for going to the next line after progress completion. Status ="" # Calcuting progress between 0 and 1 for percentage. Progress = float(Progress) / float(Total) # Doing this conditions at final progressing. if Progress >= 1.: Progress = 1 Status =" " # Going to the next line # Calculating how many places should be filled Block = int(round(BarLength * Progress)) # Show this Bar ="[{}] {:.0f}% {}".format(ProgressIcon * Block + BarIcon * (BarLength - Block), round(Progress * 100, 0), Status) return Bar except: return"ERROR" def ShowBar(Bar): sys.stdout.write(Bar) sys.stdout.flush() if __name__ == '__main__': print("This is a simple progress bar. ") # Example #1: print('Example #1') Runs = 10 for i in range(Runs + 1): progressBar =" Progress:" + ProgressBar(10, i, Runs) ShowBar(progressBar) time.sleep(1) # Example #2: print(' Example #2') Runs = 10 for i in range(Runs + 1): progressBar =" Progress:" + ProgressBar(10, i, 20, '|', '.') ShowBar(progressBar) time.sleep(1) print(' Done.') # Example #2: Runs = 10 for i in range(Runs + 1): ProgressBar(10, i) time.sleep(1) |
结果:
This is a simple progress bar.
Example #1
Progress: [###-------] 30%
Example #2
Progress: [||||||||||||........] 60%
Done.
试试PyProg。 PyProg是一个Python的开源库,可以创建超级自定义的进度指示器。酒吧。
目前版本为1.0.2;它托管在Github上,可在PyPI上获得(下面的链接)。它与Python 3&amp; 2,它也可以用于Qt控制台。
它真的很容易使用。以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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() |
将产生:
1 2 3 4 5 6 7 8 | Initial State: Progress: 0% -------------------------------------------------- When half done: Progress: 50% #########################------------------------- Final State: Progress: 100% ################################################## |
我实际上制作了PyProg,因为我需要一个简单但超级可自定义的进度条库。您可以使用
PyProg Github:https://github.com/Bill13579/pyprog
PyPI:https://pypi.python.org/pypi/pyprog/
如果您的工作无法分解为可测量的块,您可以在新线程中调用函数并计算所需的时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import thread import time import sys def work(): time.sleep( 5 ) def locked_call( func, lock ): lock.acquire() func() lock.release() lock = thread.allocate_lock() thread.start_new_thread( locked_call, ( work, lock, ) ) # This part is icky... while( not lock.locked() ): time.sleep( 0.1 ) while( lock.locked() ): sys.stdout.write("*" ) sys.stdout.flush() time.sleep( 1 ) print" Work Done" |
显然,您可以根据需要提高定时精度。
jelde015的更通用的答案(当然可归功于他)
手动更新加载栏将是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import sys from math import * def loadingBar(i, N, size): percent = float(i) / float(N) sys.stdout.write(" " + str(int(i)).rjust(3, '0') +"/" +str(int(N)).rjust(3, '0') + ' [' + '='*ceil(percent*size) + ' '*floor((1-percent)*size) + ']') |
并通过以下方式调用:
1 | loadingBar(7, 220, 40) |
将导致:
1 | 007/220 [= ] |
只需在当前的
将
要以有用的方式使用任何进度条框架,即获得实际进度百分比和估计的ETA,您需要能够声明它将具有多少步骤。
那么,你的计算函数在另一个线程中,你能够在多个逻辑步骤中拆分它吗?你能修改它的代码吗?
您不需要重构它或在实际方法中拆分,您可以在其中的某些位置放置一些战略性的
这样,你的功能可能是这样的:
1 2 3 4 5 6 7 | def compute(): time.sleep(1) # some processing here yield # insert these time.sleep(1) yield time.sleep(1) yield |
或这个:
1 2 3 4 | def compute(): for i in range(1000): time.sleep(.1) # some processing here yield # insert these |
使用这种功能,您可以安装:
1 | pip install alive-progress |
并使用它像:
1 2 3 4 5 | from alive_progress import alive_bar with alive_bar(3) as bar: for i in compute(): bar() |
要获得一个很酷的进度吧!
1 | |█████████████▎ | ▅▃▁ 1/3 [33%] in 1s (1.0/s, eta: 2s) |
免责声明:我是alive_bar的作者,但它应该很好地解决你的问题。阅读https://github.com/rsalmei/alive-progress上的文档,以下是它可以做的一个示例:
猜猜我有点晚了,但这应该适用于使用当前版本的python 3的人,因为它使用"f-strings",如Python 3.6 PEP 498中所介绍的:
码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from numpy import interp class Progress: def __init__(self, value, end, title='Downloading',buffer=20): self.title = title #when calling in a for loop it doesn't include the last number self.end = end -1 self.buffer = buffer self.value = value self.progress() def progress(self): maped = int(interp(self.value, [0, self.end], [0, self.buffer])) print(f'{self.title}: [{"#"*maped}{"-"*(self.buffer - maped)}]{self.value}/{self.end} {((self.value/self.end)*100):.2f}%', end=' ') |
例
1 2 3 | #some loop that does perfroms a task for x in range(21) #set to 21 to include until 20 Progress(x, 21) |
产量
1 | Downloading: [########------------] 8/20 40.00% |
@Massagran:它在我的程序中运行良好。此外,我们需要添加一个计数器来指示循环时间。此计数器作为方法
例如:读取测试文件的所有行并对其进行处理。假设函数
1 2 3 4 5 6 7 8 9 | 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:[cc lang="python"] dosth(); i += 1 pbar.update(i) |
pbar.finish()
代码> PRE>
变量
这是创建进度条的简单方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import time,sys toolbar_width = 50 # setting up toolbar [-------------------------------------] sys.stdout.write("[%s]"%(("-")*toolbar_width)) sys.stdout.flush() # each hash represents 2 % of the progress for i in range(toolbar_width): sys.stdout.write(" ") # return to start of line sys.stdout.flush() sys.stdout.write("[")#Overwrite over the existing text from the start sys.stdout.write("#"*(i+1))# number of # denotes the progress completed sys.stdout.flush() time.sleep(0.1) |
您应该将进度条链接到手头的任务(以便它测量进度:D)。例如,如果你正在FTP文件,你可以告诉ftplib获取一个特定大小的缓冲区,假设128K,然后你添加到你的进度条128k所代表的文件大小百分比。如果您使用CLI,并且进度表长度为20个字符,则在传输文件的1/20时添加一个字符。
使用os_sys lib:
我将它用于许多类型的酒吧,例如:
bar = Bar('progresing: ', max=20)
for i in range(20):
#do somthing
bar.next()
bar.finish()
你的输出将是:
1 | procesing: |###### | 2/10 |
在os_sys的描述中阅读更多内容