如何打印出状态栏和百分比?

实现如下所示的状态栏:

[==========                ]  45%
[================          ]  60%
[==========================] 100%

我想把这个打印到标准输出,并保持刷新,而不是打印到另一行。如何做到这一点?

261522 次浏览

你可以使用\r (回车)。演示:

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()

'\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上运行。

你可以从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

在这里你可以使用以下代码作为函数:

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()

根据上面的答案和其他类似的关于CLI进度条的问题,我想我得到了一个普遍的答案。检查https://stackoverflow.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%

我发现有用的库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可以包装任何可迭代对象。

在这里和其他地方的一些答案的基础上,我编写了这个简单的函数,它显示一个进度条和经过/估计的剩余时间。应该在大多数基于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

在尝试了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的内置控制台时,换行符仍然/再次出现。由于我花了一些时间来弄清楚,我想在这里报告这一观察结果。

这是一个非常简单的方法,可以用于任何循环。

#!/usr/bin/python
for i in range(100001):
s =  ((i/5000)*'#')+str(i)+(' %')
print ('\r'+s),

如果你正在开发一个命令行界面,我建议你看看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%

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/ < / p >

最简单的还是

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()

关键是将整数类型转换为字符串。

使用@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)

Mark Rushakoff的解决方案中所述,你可以输出回车字符sys.stdout.write('\r')来将光标重置到行首。要泛化该解决方案,同时实现Python 3的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_bar}s}] {int(100 * j)}%")
sys.stdout.flush()


sleep(0.05)
# do something with <item> here

只使用内置的sys尝试这个函数:

import sys


def print_progress_bar(index, total, label):
n_bar = 50  # Progress bar width
progress = index / total
sys.stdout.write('\r')
sys.stdout.write(f"[{'=' * int(n_bar * progress):{n_bar}s}] {int(100 * progress)}%  {label}")
sys.stdout.flush()

用法:

foo_list = ["a", "b", "c", "d"]
total = len(foo_list)


for index, item in enumerate(foo_list):
print_progress_bar(index, total, "foo bar")
sleep(0.5)

enumerate(foo_list)让你在循环期间访问索引值。

输出:

[================================================  ] 96%  foo bar

下面是我使用@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("")
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_bar}s}] {int(100 * j)}% ")
sys.stdout.flush()

电话:

printProgressBar(30,"IP")

知识产权 | [ ████████████ ----------------------------] 30%

根据Steven C. Howell对Mark Rushakoff的回答的评论

j = (i + 1) / n
stdout.write('\r')
stdout.write('[%-20s] %d%%' % ('='*int(20*j), 100*j))
stdout.flush()

其中i是当前项目和n是项目的总数

对于Python 3.6,以下工作用于更新输出内联:

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()

要成为纯python并且不进行系统调用:

from time import sleep


for i in range(21):
spaces = " " * (20 - i)
percentage = 5*i
print(f"\r[{'='*i}{spaces}]{percentage}%", flush=True, end="")
sleep(0.25)
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()

enter image description here

没有一个答案能完全满足我的需求。所以我写了我自己的,如上所示。我需要的功能:

  • 只传递步数和总步数,它就完成了计算完成百分比的困难工作。
  • 用60个字,分成480个“勾”字;每tick产出0.21%。如果没有勾号,每个字符只占1.67%。
  • 支持将标题放在前面。
  • 行尾完成百分比可选。
  • 可变长度的进度条,默认为60个字符或480个“滴答”。
  • 设置进度条颜色,默认为绿色。

如何调用进度显示

调用进度显示非常简单。对于上面的.gif示例,函数调用使用:

percent_complete(step, total_steps, title="Convert Markdown")

在CSV格式的堆栈交换数据转储中,total_stepslen(rows)约为2500。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


# UTF-8 left blocks: 1, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8
utf_8s = ["█", "▏", "▎", "▍", "▌", "▋", "▊", "█"]
perc = 100 * float(step) / float(total_steps)
max_ticks = bar_width * 8
num_ticks = int(round(perc / 100 * max_ticks))
full_ticks = num_ticks / 8      # Number of full blocks
part_ticks = num_ticks % 8      # Size of partial block (array index)
    

disp = bar = ""                 # Blank out variables
bar += utf_8s[0] * int(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 += "▒" * int((max_ticks/8 - float(num_ticks)/8.0))
    

if len(title) > 0:
disp = title + ": "         # Optional title to progress display
    

# Print progress bar in green: https://stackoverflow.com/a/21786287/6929343
disp += "\x1b[0;32m"            # Color Green
disp += bar                     # Progress bar to progress display
disp += "\x1b[0m"               # Color Reset
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关键字参数default可以在调用函数时通过传递print_perc=False来覆盖。这将允许一个更长的进度条。
  • title=""关键字参数默认为no title。如果你想要使用title="My Title": 将自动添加到它。
  • 当你的程序完成时,记得调用sys.stdout.write("\r")sys.stdout.flush()来清除进度显示行。

总结

这个答案比其他答案长一点,但重要的是要注意它是一个完整的解决方案,而不是需要添加更多代码的解决方案的一部分。

另一点是这个解决方案没有依赖关系,也不需要安装任何额外的东西。Python支持UTF-8字符集,并且gnome-terminal不需要额外的设置。如果你使用的是Python 2.7,在shebang之后可能需要# -*- coding: utf-8 -*-。IE作为程序的第二行。

该函数可以转换为具有独立initupdatepause(用于将调试内容打印到屏幕上)、resumeclose方法的类。

这个函数是从bash脚本转换过来的:

bash脚本将显示索尼电视音量libnotify-bin(弹出气泡消息)每当电视音量被改变。如果您对bash进度条感兴趣,请访问Stack Overflow链接。

编辑于2022年1月30日

  • 每个角色从4个刻度改为8个刻度。
  • 移除整块之间的间隙。
  • 添加颜色支持。