当我的脚本执行一些可能需要时间的任务时,如何使用进度条呢?
例如,在完成某个函数并返回True
时需要一定的时间。我如何在函数执行期间显示进度条呢?
请注意,我需要实时显示进度条,所以我不知道该怎么办。我需要为此使用thread
吗?我不知道。
目前我在函数执行期间没有任何打印输出,但一个进度条会很好。我更关心的是从代码角度如何实现这一点。
当我的脚本执行一些可能需要时间的任务时,如何使用进度条呢?
例如,在完成某个函数并返回True
时需要一定的时间。我如何在函数执行期间显示进度条呢?
请注意,我需要实时显示进度条,所以我不知道该怎么办。我需要为此使用thread
吗?我不知道。
目前我在函数执行期间没有任何打印输出,但一个进度条会很好。我更关心的是从代码角度如何实现这一点。
使用 tqdm (conda install tqdm
或者 pip install tqdm
),你可以在一秒钟内为你的循环添加进度条:
from time import sleep
from tqdm import tqdm
for i in tqdm(range(10)):
sleep(3)
60%|██████ | 6/10 [00:18<00:12, 0.33 it/s]
此外,还有一个笔记本版本:
from tqdm.notebook import tqdm
for i in tqdm(range(100)):
sleep(3)
你可以使用 tqdm.auto
代替 tqdm.notebook
来在终端和笔记本中工作。
tqdm.contrib
包含一些辅助函数,例如enumerate
、map
和 zip
。在tqdm.contrib.concurrent
中有并行映射。
甚至可以使用tqdm.contrib.telegram
或tqdm.contrib.discord
在从jupyter笔记本断开连接后将进度发送到您的手机。
__len__
属性,或者用户必须向tqdm
提供total
参数。否则,进度条将正常工作但没有ETA。 - gaborousfrom tqdm import tqdm_notebook as tqdm
。否则请勿将其写在一行中。 - Jacques MALAPRADEpip install alive-progress
,你就可以开始了!
要有效地使用任何进度条,即获得完成百分比和预计剩余时间,您需要能够告诉它总项目数。然后,alive-progress
将跟踪您当前的处理位置以及需要多长时间!
alive-progress
仍然可以工作。alive-progress
的进度条:def compute():
with alive_bar(1000) as bar: # your expected total
for item in items: # the original loop
print(item) # your actual processing here
bar() # call `bar()` at the end
compute()
或者,如果您希望保持代码隔离,只需在处理代码中插入 yield
(以标记项目已处理),然后像这样驱动 alive-progress
的进度条:
def compute():
for item in items:
print(item)
yield # simply insert this :)
with alive_bar(1000) as bar:
for i in compute():
bar()
|█████████████▎ | ▅▃▁ 321/1000 [32%] in 8s (40.1/s, eta: 16s)
它支持很多高级选项,开箱即用!
免责声明:我是《alive-progress》的自豪作者,在 GitHub 上获得了4.6K+⭐️的赞!
阅读文档https://github.com/rsalmei/alive-progress以了解所有高级功能。
请看一下它在旋转器和进度条小部件中可以实现的更多动画效果:
它还适用于 Jupyter Notebooks!
您甚至可以设计自己的动画!
with open(path2file, 'wb+') as f: # with open(path2file, 'w+') as f: f.write(data.read())
- Charlie Parkerbar(size)
即可。 - rsalmei有特定的库(像这里的这个),但也许一些非常简单的东西也可以:
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 range(toolbar_width):
time.sleep(0.1) # do real work here
# update the bar
sys.stdout.write("-")
sys.stdout.flush()
sys.stdout.write("]\n") # this ends the progress bar
注意:progressbar2是 progressbar的分支,后者已经多年未得到维护。xrange
在Python 3中等同于 range
。 - quapkaprint('■', end='', flush=True)
- PatrickTimport sys
import time
def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.6+
count = len(it)
start = time.time()
def show(j):
x = int(size*j/count)
remaining = ((time.time() - start) / j) * (count - j)
mins, sec = divmod(remaining, 60)
time_str = f"{int(mins):02}:{sec:05.2f}"
print(f"{prefix}[{u'█'*x}{('.'*(size-x))}] {j}/{count} Est wait {time_str}", end='\r', file=out, flush=True)
for i, item in enumerate(it):
yield item
show(i+1)
print("\n", flush=True, file=out)
[████████████████████████████.........................] 24/50 Est wait 00:05.38
import time
for i in progressbar(range(15), "Computing: ", 40):
time.sleep(0.1) # any code you need
不需要第二个线程。一些解决方案/包需要。
适用于任何可迭代对象,也就是任何可以使用len()
的对象。例如,一个list
,一个dict
,例如['a', 'b', 'c' ... 'g']
适用于生成器,只需要用list()
将其包装起来。例如for i in progressbar(list(your_generator), "Computing: ", 40):
除非工作是在生成器中完成。在这种情况下,您需要另一种解决方案(如tqdm)。
您还可以通过将out
更改为sys.stderr
来更改输出,例如。
import sys
def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.3+
count = len(it)
def show(j):
x = int(size*j/count)
print("{}[{}{}] {}/{}".format(prefix, "#"*x, "."*(size-x), j, count),
end='\r', file=out, flush=True)
show(0)
for i, item in enumerate(it):
yield item
show(i+1)
print("\n", flush=True, file=out)
import sys
def progressbar(it, prefix="", size=60, out=sys.stdout):
count = len(it)
def show(j):
x = int(size*j/count)
out.write("%s[%s%s] %i/%i\r" % (prefix, u"#"*x, "."*(size-x), j, count))
out.flush()
show(0)
for i, item in enumerate(it):
yield item
show(i+1)
out.write("\n")
out.flush()
TypeError: object of type 'generator' has no len()
。 - jabellcu█
替换了#
字符。这是我制作的一个要点:https://gist.github.com/ChesterChowWOV/2b35c551b339adbf459363322aac5b4b - ChesterWOV以上建议都很好,但我认为大多数人只想要一个现成的解决方案,不依赖外部包,同时也可重复使用。
我汲取了所有建议中最好的要点,并将其制作成一个函数,附带测试用例。
要使用它,只需复制“def update_progress(progress)”下面的行,但不包括测试脚本。别忘了导入sys。每当需要显示或更新进度条时,请调用此函数。
该方法通过直接向控制台发送“\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(101):
time.sleep(0.1)
update_progress(i/100.0)
print ""
print "Test completed"
time.sleep(10)
这是测试脚本结果显示的内容(最后一个进度条会动画显示):
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: [##########] 100% Done...
Test completed
print(...,end ='')
而不是调用stdout.write()+ stdout.flush()
。2)如果您将\r
放在字符串末尾而不是开头,则与其他控制台输出更加协调。 - Tim Sparklestext = "\r百分比: [{0}] {1:.2f}% {2}".format( "#"*block + "-"*(barLength-block), progress*100, status)
。 - Kory Gill尝试使用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
progress
可以制作出漂亮的进度条,但如果其他软件正在操作 stderr
,它就会失败。很抱歉,我还没有调查清楚具体的问题。 - Arthur对于一个类似的应用(在循环中跟踪进度),我只是使用了python-progressbar:
他们的示例大致如下:
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
progressbar2
包。上述代码将与其一起正常工作。 - d33tahimport *
吗? - eric在这里搜索了一个类似的解决方案之后,我为自己的需求刚刚制作了一个简单的进度类。我想我可以将其发布出来。
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个任务
__call__
的结尾处增加progress.current
的递增操作可以更进一步地减少主代码与对象的交互。 - npit我喜欢 Brian Khuu的答案,因为它很简单且不需要外部包。我稍微修改了一下,所以在这里添加我的版本:
import sys
import time
def updt(total, progress):
"""
Displays or updates a console progress bar.
Original source: https://dev59.com/XXA75IYBdhLWcg3wrrNS#15860757
"""
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%
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分钟,并且呈现如下:
Adding Users: 3%|█████▊ [ time left: 04:51 ]
你可以根据自己的喜好进行更改和定制。
with open(path2file, 'wb+') as f: # with open(path2file, 'w+') as f: f.write(data.read())
- Charlie Parker