Python进度条
当我的脚本正在做一些可能需要时间的任务时,如何使用进度条?
例如,一个需要一些时间才能完成的函数,完成后返回True
。 如何在函数执行期间显示进度条?
请注意,我需要这个实时,所以我不知道该怎么做。 我需要一个thread
吗? 我不知道。
现在我不打印任何东西,而function正在执行,但进度条会很好。 另外,我更关心如何从代码的angular度来完成这个工作。
有一些特定的库( 比如这里 ),但也许很简单:
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("\n")
注意:这个进度条是进度条的一个分支,它没有被维护多年。
使用tqdm,您可以在第二个循环中添加一个进度表:
In [20]: import time In [21]: from tqdm import * In [23]: for i in tqdm(range(10)): ....: time.sleep(3) 60%|██████ | 6/10 [00:18<00:12, 0.33 it/s]
上面的build议是相当不错的,但我想大多数人只是想要一个现成的解决scheme,没有外部包的依赖,但也是可重用的。
我得到了以上所有的最好的观点,并且把它变成了一个函数,以及一个testing用例。
要使用它,只需复制“def update_progress(progress)”下面的行,而不是testing脚本。 不要忘记导入系统。 每当需要显示或更新进度栏时调用此方法。
这是通过直接发送“\ r”符号到控制台来移动光标回到起点。 python中的“print”并没有为这个目的识别上面的符号,因此我们需要'sys'
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\r\n" if progress < 0: progress = 0 status = "Halt...\r\n" if progress >= 1: progress = 1 status = "Done...\r\n" block = int(round(barLength*progress)) text = "\rPercent: [{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)
这是testing脚本的结果显示(最后一个进度条animation):
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
对于一个类似的应用程序(跟踪循环中的进展),我只是使用python进度条 :
他们的榜样是这样的,
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() print
在这里search一个等效的解决scheme后,我刚刚为我的需求做了一个简单的进度类。 我强硬,我可能会很好地张贴它。
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('\r' + self.fmt % args, file=self.output, end='') def done(self): self.current = self.total self() print('', file=self.output)
例如:
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()
将打印以下内容:
[======== ] 17/80 ( 21%) 63 to go
从https://pypi.python.org/pypi/progress尝试进度。;
from progress.bar import Bar bar = Bar('Processing', max=20) for i in range(20): # Do some work bar.next() bar.finish()
结果将是一个如下的酒吧:
Processing |############# | 42/100
我真的很喜欢Python的进度条 ,因为它使用起来非常简单。
最简单的情况就是:
import progressbar import time progress = progressbar.ProgressBar() for i in progress(range(80)): time.sleep(0.01)
外观可以定制,可以显示预计的剩余时间。 例如,使用与上面相同的代码,但是:
progress = progressbar.ProgressBar(widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage(), ' ', progressbar.ETA()])
我喜欢Brian Khuu的简单而不需要外部软件包的答案 。 我改变了一下,所以我在这里添加我的版本:
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, "\r\n" block = int(round(barLength * progress)) text = "\r[{}] {:.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)
假设total >= progress
它取得总运行次数( total
)和迄今处理的运行次数( progress
)。 结果如下所示:
[#####---------------] 27%
上面的许多答案都依赖于外部包,但是我也认为(正如上面所说的那样)大多数人只是想要一个现成的解决scheme。 下面的代码可以通过自定义string部分来适应您的需要。
这是更简单的工作,而不需要第二个线程来更新栏。 上面的一些包做这个。 第二个线程可能是ipython笔记本的一个问题。
下面的代码只能用于提供长度的迭代器(即,必须定义len(迭代器))。
import sys def progressbar(it, prefix="", size=60): count = len(it) def _show(_i): x = int(size*_i/count) sys.stdout.write("%s[%s%s] %i/%i\r" % (prefix, "#"*x, "."*(size-x), _i, count)) sys.stdout.flush() _show(0) for i, item in enumerate(it): yield item _show(i+1) sys.stdout.write("\n") sys.stdout.flush()
例:
import time for i in progressbar(range(15), "Computing: ", 40): time.sleep(0.1) # any calculation you need
输出:
Computing: [........................................] 0/15
…
Computing: [########................................] 3/15
…
Computing: [########################################] 15/15
it
可以是任何具有len
可迭代对象,例如['a','b','c']`工作得很好。
使用这个库: fish
( GitHub )。
用法:
>>> import fish >>> while churning: ... churn_churn() ... fish.animate()
玩的开心!
我喜欢这个页面 。
从简单的例子开始,并转到multithreading版本。 开箱即用。 没有第三方包需要。
代码将如下所示:
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)
或者这里是使用线程的例子,以便在程序运行时运行旋转加载栏:
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
如果你的工作不能被分解成可测量的块,你可以在一个新的线程和时间内调用你的函数需要多长时间:
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 "\nWork Done"
您可以根据需要明显提高定时精度。
这是一个简短的解决scheme,以编程方式构build加载栏(您必须决定需要多长时间)。
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('\r%s Loading at %3d percent!' % (loading, i*100/n), end='') loading = loading[:i] + '#' + loading[i+1:] time.sleep(load)
你应该把进度条连接到手边的任务(这样它就可以测量进度:D)。 例如,如果你正在FTP文件,你可以告诉ftplib抓取一个特定大小的缓冲区,比如说128K,然后你可以在你的进度条中添加128k文件大小的任何百分比。 如果您使用的是CLI,并且您的进度表长度为20个字符,则在文件的1/20处传输完毕后,您将添加一个字符。
@Massagran:在我的程序中效果很好。 此外,我们需要添加一个计数器来指示循环时间。 该计数器作为方法update
的参数。 例如:读取一个testing文件的所有行,并将其处理。 假设函数dosth()
在variablesi
不涉及。
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()
variablesi
通过方法update
控制pbar
的状态
我喜欢Gabriel的回答,但我改变了它的灵活性。 您可以将长度发送到该function,并获得您想要的任何长度的进度栏。 你不能有一个零或负长度的进度栏。 另外,你可以使用Gabriel这个函数来回答(请看例2)。
import sys import time def ProgressBar(Total, Progress, BarLength=20): # 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 = "\r\n" # Going to the next line # Calculating how many places should be filled Block = int(round(BarLength * Progress)) # Show this Text = "\r[{}] {:.0f}% {}".format("#" * Block + "-" * (BarLength - Block), round(Progress * 100, 0), Status) sys.stdout.write(Text) sys.stdout.flush() # Example #1: Runs = 10 for i in range(Runs + 1): ProgressBar(10, i, Runs) time.sleep(1) # Example #2: Runs = 10 for i in range(Runs + 1): ProgressBar(10, i) time.sleep(1)
如果它是一个固定迭代次数的大循环,花费很多时间,你可以使用这个函数。 循环的每个迭代都会添加进度。 其中count是循环的当前迭代,total是您要循环的值,size(int)是您希望以10为增量增加的大小(大小1 = 10个字符,大小2 = 20个字符)
import sys def loadingBar(count,total,size) percent = float(count)/float(total)*100 sys.stdout.write("\r" + str(int(count)).rjust(3,'0')+"/"+str(int(total)).rjust(3,'0') + ' [' + '='*int(percent/10)*size + ' '*(10-int(percent/10))*size + ']')
例:
for i in range(0,100): loadingBar(i,100,2) #do some code
输出:
i = 50 >> 050/100 [========== ]