Python打印状态栏和百分比
Posted
技术标签:
【中文标题】Python打印状态栏和百分比【英文标题】:Python to print out status bar and percentage 【发布时间】:2011-03-01 10:24:01 【问题描述】:实现如下状态栏:
[========== ] 45%
[================ ] 60%
[==========================] 100%
我希望将其打印到标准输出,并不断刷新它,而不是打印到另一行。如何做到这一点?
【问题讨论】:
我发布了一种新的进度条,除了非常酷的动画外,您还可以打印、查看吞吐量和 eta,甚至暂停它!请看:github.com/rsalmei/alive-progress!alive-progress 【参考方案1】:发布的答案都没有完全满足我的需求。所以我写了我自己的,如上图所示。我需要的功能:
只传递步数和总步数,它完成了计算完成百分比的艰巨工作。 仅使用 60 个字符空间,将它们分成 240 个“刻度”,以提供从 0.25 % 到 100% 的更精细的显示。 支持添加标题。 可选百分比在行尾完成。 可变长度进度条,默认为 60 个字符或 240 个“记号”。如何调用进度显示
调用进度显示非常简单。对于上面的示例.gif
,该函数是使用以下方法调用的:
percent_complete(step, total_steps, title="Convert Markdown")
在 CSV 格式的 Stack Exchange 数据转储中,len(rows)
的 total_steps
约为 2,500。 step
是当前行号,因为每个 Stack Exchange Markdown Q&A 都转换为 Kramdown(用于 GitHub Pages)。
Python 代码
代码很简单,但比其他答案长一点:
def percent_complete(step, total_steps, bar_width=60, title="", print_perc=True):
import sys
fill = "▒" # Fill up to bar_width
utf_8s = ["▉", "▎", "▌", "▊"] # UTF-8 left blocks: 7/8, 1/4, 1/2, 3/4
perc = 100 * float(step) / float(total_steps)
max_ticks = bar_width * 4
num_ticks = int(round(perc / 100 * max_ticks))
full_ticks = num_ticks / 4 # Number of full blocks
part_ticks = num_ticks % 4 # Size of partial block (array index)
disp = bar = "" # Blank out variables
bar += utf_8s[0] * full_ticks # Add full blocks into Progress Bar
# If part_ticks is zero, then no partial block, else append part char
if part_ticks > 0:
bar += utf_8s[part_ticks]
# Pad Progress Bar with fill character
bar += fill * int((max_ticks/4 - float(num_ticks)/4.0))
if len(title) > 0:
disp = title + ": " # Optional title to progress display
disp += bar # Progress bar to progress display
if print_perc:
# If requested, append percentage complete to progress display
if perc > 100.0:
perc = 100.0 # Fix "100.04 %" rounding error
disp += " :6.2f".format(perc) + " %"
# Output to terminal repetitively over the same line using '\r'.
sys.stdout.write("\r" + disp)
sys.stdout.flush()
Python 代码注释
几点:
[ .... ]
方括号占位符不是必需的,因为存在用于相同目的的填充字符。这样可以节省两个额外字符以使进度条更宽。
bar_width
关键字参数可以根据屏幕宽度使用。 60
的默认值似乎适合大多数用途。
print_perc=True
关键字参数默认值可以通过在调用函数时传递print_perc=False
来覆盖。这将允许更长的进度条。
title=""
关键字参数默认为无标题。如果您希望使用一次,title="My Title"
和 :
将自动添加到其中。
当您的程序完成后,记得调用sys.stdout.write("\r")
后跟sys.stdout.flush()
以清除进度显示行。
总结
这个答案比其他答案长一点,但重要的是要注意它是一个完整的解决方案,而不是您需要添加更多代码的解决方案的一部分。
另一点是这个解决方案没有依赖项,也没有额外的安装。 Python 支持 UTF-8 字符集,gnome-terminal
不需要额外的设置。如果您使用的是 Python 2.7,则可能需要在 shebang 之后使用# -*- coding: utf-8 -*-
。 IE 作为程序的第二行。
该函数可以转换为具有单独 init
、update
、pause
(用于将调试内容打印到屏幕)、resume
和 close
方法的类。
此函数是从 bash 脚本转换而来的。每当电视音量发生变化时,bash 脚本都会以libnotify-bin
(弹出气泡消息)显示索尼电视音量。如果您对 bash 版本感兴趣,请在下面发表评论。
【讨论】:
【参考方案2】:import progressbar
import time
# Function to create
def animated_marker():
widgets = ['Loading: ', progressbar.Bar('=', '[', ']', '-'), progressbar.Percentage()]
bar = progressbar.ProgressBar(max_value=200,widgets=widgets).start()
for i in range(200):
time.sleep(0.1)
bar.update(i+1)
bar.finish()
# Driver's code
animated_marker()
【讨论】:
【参考方案3】:做纯python,不做系统调用:
from time import sleep
for i in range(21):
spaces = " " * (20 - i)
percentage = 5*i
print(f"\r['='*ispaces]percentage%", flush=True, end="")
sleep(0.25)
【讨论】:
【参考方案4】:对于 Python 3.6,我可以通过以下方式更新输出 inline:
for current_epoch in range(10):
for current_step) in range(100):
print("Train epoch %s: Step %s" % (current_epoch, current_step), end="\r")
print()
【讨论】:
【参考方案5】:根据 Steven C. Howell 对 Mark Rushakoff's answer 的评论
j = (i + 1) / n
stdout.write('\r')
stdout.write('[%-20s] %d%%' % ('='*int(20*j), 100*j))
stdout.flush()
其中i
是当前项目,n
是项目总数
【讨论】:
【参考方案6】:def printProgressBar(value,label):
n_bar = 40 #size of progress bar
max = 100
j= value/max
sys.stdout.write('\r')
bar = '█' * int(n_bar * j)
bar = bar + '-' * int(n_bar * (1-j))
sys.stdout.write(f"label.ljust(10) | [bar:n_bars] int(100 * j)% ")
sys.stdout.flush()
呼叫:
printProgressBar(30,"IP")
知识产权 | [████████████----------------------------] 30%
【讨论】:
【参考方案7】:这是我使用@Mark-Rushakoff 的解决方案所做的。自适应调整终端宽度。
from time import sleep
import os
import sys
from math import ceil
l = list(map(int,os.popen('stty size','r').read().split()))
col = l[1]
col = col - 6
for i in range(col):
sys.stdout.write('\r')
getStr = "[%s " % ('='*i)
sys.stdout.write(getStr.ljust(col)+"]"+"%d%%" % (ceil((100/col)*i)))
sys.stdout.flush()
sleep(0.25)
print("")
【讨论】:
【参考方案8】:进一步改进,使用函数作为:
import sys
def printProgressBar(i,max,postText):
n_bar =10 #size of progress bar
j= i/max
sys.stdout.write('\r')
sys.stdout.write(f"['=' * int(n_bar * j):n_bars] int(100 * j)% postText")
sys.stdout.flush()
调用示例:
total=33
for i in range(total):
printProgressBar(i,total,"blah")
sleep(0.05)
输出:
[================================================ ] 96% blah
【讨论】:
完美!并且不需要任何模块【参考方案9】:如Mark Rushakoff's solution 中所述,您可以输出回车符sys.stdout.write('\r')
,将光标重置到行首。为了推广该解决方案,同时实现Python 3's f-Strings,您可以使用
from time import sleep
import sys
n_bar = 50
iterable = range(33) # for demo purposes
n_iter = len(iterable)
for i, item in enumerate(iterable):
j = (i + 1) / n_iter
sys.stdout.write('\r')
sys.stdout.write(f"['=' * int(n_bar * j):n_bars] int(100 * j)%")
sys.stdout.flush()
sleep(0.05)
# do something with <item> here
【讨论】:
【参考方案10】:使用@Mark-Rushakoff 答案,我制定了一种更简单的方法,无需调用 sys 库。它适用于 Python 3。在 Windows 中测试:
from time import sleep
for i in range(21):
# the exact output you're looking for:
print ("\r[%-20s] %d%%" % ('='*i, 5*i), end='')
sleep(0.25)
【讨论】:
如the answer to a different question 中所述,print
是一个瘦包装器,用于格式化输入并调用给定对象的写入函数。默认情况下,此对象为sys.stdout
。【参考方案11】:
这里你可以使用以下代码作为函数:
def drawProgressBar(percent, barLen = 20):
sys.stdout.write("\r")
progress = ""
for i in range(barLen):
if i < int(barLen * percent):
progress += "="
else:
progress += " "
sys.stdout.write("[ %s ] %.2f%%" % (progress, percent * 100))
sys.stdout.flush()
使用 .format:
def drawProgressBar(percent, barLen = 20):
# percent float from 0 to 1.
sys.stdout.write("\r")
sys.stdout.write("[:<] :.0f%".format("=" * int(barLen * percent), barLen, percent * 100))
sys.stdout.flush()
【讨论】:
对我来说,第一行不会被光标修改 - 只有第二行会。因此,进度条获得了多行,例如] percent * 100 %
第二个功能很好,但我必须补充:if percent == 1: print('')【参考方案12】:
最简单的还是
import sys
total_records = 1000
for i in range (total_records):
sys.stdout.write('\rUpdated record: ' + str(i) + ' of ' + str(total_records))
sys.stdout.flush()
关键是将整数类型转换为字符串。
【讨论】:
【参考方案13】:试试 PyProg。 PyProg 是一个用于 Python 的开源库,用于创建超级可定制的进度指示器和条形图。
目前是 1.0.2 版本;它托管在 Github 上并在 PyPI 上可用(链接如下)。它与 Python 3 & 2 兼容,也可以与 Qt 控制台一起使用。
它真的很容易使用。以下代码:
import pyprog
from time import sleep
# Create Object
prog = pyprog.ProgressBar(" ", " ", total=34, bar_length=26, complete_symbol="=", not_complete_symbol=" ", wrap_bar_prefix=" [", wrap_bar_suffix="] ", progress_explain="", progress_loc=pyprog.ProgressBar.PROGRESS_LOC_END)
# 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()
会产生你想要的(甚至是条的长度!):
[=========== ] 45%
[=============== ] 60%
[==========================] 100%
有关自定义进度条的更多选项,请转到本网站的 Github 页面。
我实际上制作了 PyProg,因为我需要一个简单但超级可定制的进度条库。您可以通过以下方式轻松安装它:pip install pyprog
。
PyProg Github:https://github.com/Bill13579/pyprog PyPI:https://pypi.python.org/pypi/pyprog/
【讨论】:
【参考方案14】:如果你正在开发命令行界面,我建议你看一下click
,非常不错:
import click
import time
for filename in range(3):
with click.progressbar(range(100), fill_char='=', empty_char=' ') as bar:
for user in bar:
time.sleep(0.01)
这是你得到的输出:
$ python test.py
[====================================] 100%
[====================================] 100%
[========= ] 27%
【讨论】:
【参考方案15】:您可以从PyPI 获得一个名为progressbar
的Python 模块,该模块实现了此类功能。如果您不介意添加依赖项,这是一个很好的解决方案。否则,请选择其他答案之一。
一个简单的使用例子:
import progressbar
from time import sleep
bar = progressbar.ProgressBar(maxval=20, \
widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()])
bar.start()
for i in xrange(20):
bar.update(i+1)
sleep(0.1)
bar.finish()
要安装它,你可以使用easy_install progressbar
,如果你喜欢pip,你可以使用pip install progressbar
。
【讨论】:
所有答案都很棒,但是,我最喜欢模块。谢谢大家。 遗憾的是,progressbar
和 fish
似乎都不适用于 python3。
没关系,我fixed fish
to work with python3。
此模块已超过 2 年未更新。不要将它用于新软件!
安装:sudo -H pip install progressbar2
.【参考方案16】:
这是一种非常简单的方法,可用于任何循环。
#!/usr/bin/python
for i in range(100001):
s = ((i/5000)*'#')+str(i)+(' %')
print ('\r'+s),
【讨论】:
“#”有什么作用? @unseen_rider 这里的 '#' 只是一个符号,会随着循环迭代的增加而重复。【参考方案17】:我今天遇到了这个帖子,并在尝试了 Mark Rushakoff 的这个解决方案之后
from time import sleep
import sys
for i in range(21):
sys.stdout.write('\r')
# the exact output you're looking for:
sys.stdout.write("[%-20s] %d%%" % ('='*i, 5*i))
sys.stdout.flush()
sleep(0.25)
我可以说这在带有 python 3.4.3 64 位的 W7-64 上运行良好,但只能在本机控制台中运行。但是,当使用 spyder 3.0.0dev 的内置控制台时,换行符仍然/再次存在。由于这花了我一些时间来弄清楚,我想在这里报告这个观察结果。
【讨论】:
【参考方案18】:我找到了有用的库 tqdm(https://github.com/tqdm/tqdm/,以前:https://github.com/noamraph/tqdm)。它会自动估计完成时间,并可用作迭代器。
用法:
import tqdm
import time
for i in tqdm.tqdm(range(1000)):
time.sleep(0.01)
# or other long operations
结果:
|####------| 450/1000 45% [elapsed: 00:04 left: 00:05, 99.15 iters/sec]
tqdm
可以包装任何可迭代对象。
【讨论】:
新开发团队的tqdm project is now maintained here。 哇,这个 tqdm 真是太棒了,而且很容易使用:)。 这是最简单的解决方案 它也与 Anaconda 发行版捆绑在一起! (至少对于python 3.5及以上) 谢谢,太棒了,简单有效【参考方案19】:基于此处和其他地方的一些答案,我编写了这个简单的函数,它显示一个进度条和经过/估计的剩余时间。应该可以在大多数基于 unix 的机器上工作。
import time
import sys
percent = 50.0
start = time.time()
draw_progress_bar(percent, start)
def draw_progress_bar(percent, start, barLen=20):
sys.stdout.write("\r")
progress = ""
for i in range(barLen):
if i < int(barLen * percent):
progress += "="
else:
progress += " "
elapsedTime = time.time() - start;
estimatedRemaining = int(elapsedTime * (1.0/percent) - elapsedTime)
if (percent == 1.0):
sys.stdout.write("[ %s ] %.1f%% Elapsed: %im %02is ETA: Done!\n" %
(progress, percent * 100, int(elapsedTime)/60, int(elapsedTime)%60))
sys.stdout.flush()
return
else:
sys.stdout.write("[ %s ] %.1f%% Elapsed: %im %02is ETA: %im%02is " %
(progress, percent * 100, int(elapsedTime)/60, int(elapsedTime)%60,
estimatedRemaining/60, estimatedRemaining%60))
sys.stdout.flush()
return
【讨论】:
【参考方案20】:基于上述答案和其他关于 CLI 进度条的类似问题,我想我对所有这些问题都有一个普遍的共同答案。在https://***.com/a/15860757/2254146查看它
这是该函数的副本,但已根据您的风格进行了修改:
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 = 20 # 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()
看起来像
百分比:[====================] 99.0%
【讨论】:
我没有显示进度条 我认为它不需要那么多小数位,即round(progress*100,2)【参考方案21】:您可以使用\r
(carriage return)。演示:
import sys
total = 10000000
point = total / 100
increment = total / 20
for i in xrange(total):
if(i % (5 * point) == 0):
sys.stdout.write("\r[" + "=" * (i / increment) + " " * ((total - i)/ increment) + "]" + str(i / point) + "%")
sys.stdout.flush()
【讨论】:
尝试total
为10
,然后您会收到错误消息ZeroDivisionError: long division or modulo by zero
【参考方案22】:
'\r'
字符(回车)将光标重置到行首,并允许您改写该行之前的内容。
from time import sleep
import sys
for i in range(21):
sys.stdout.write('\r')
# the exact output you're looking for:
sys.stdout.write("[%-20s] %d%%" % ('='*i, 5*i))
sys.stdout.flush()
sleep(0.25)
我不能 100% 确定这是否可以在所有系统上完全移植,但它至少可以在 Linux 和 OSX 上运行。
【讨论】:
这比标记的答案更好,因为它也适用于 Python 3。 如所写,代码并没有明确说明如何使其适应您正在迭代的任何大小(不是 21)。我会让n=21
,用range(n)
替换range(21)
,然后在循环中添加j = (i + 1) / n
,并用这个轻微的修改替换write
语句:sys.stdout.write("[%-20s] %d%%" % ('='*int(20*j), 100*j))
。现在你需要做的唯一改变是在循环之前n=21
(更可能是n=len(iterable)
),然后枚举可迭代对象。我推荐了这个编辑,但被拒绝了;显然功能“偏离了帖子的初衷”。
自适应任意大小的 n,sys.stdout.write("[:] :.1f%".format("="*i, n-1, (100/(n-1)*i)))
,仅限 Python 3
什么是%-20s
?
@StevenC.Howell 为什么不将其作为引用马克的答案发布?这是另一个版本,准备好非常有帮助以上是关于Python打印状态栏和百分比的主要内容,如果未能解决你的问题,请参考以下文章