Python打印状态栏和百分比


160

要实现如下状态栏:

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

我希望将此打印到stdout,并保持刷新状态,而不是打印到另一行。这该怎么做?


我发布了一种新型的进度条,除了非常酷的动画外,您还可以打印,查看吞吐量和eta甚至暂停它!请看一下:github.com/rsalmei/alive-progress实时进展
rsalmei

Answers:


146

您可以从中获得一个Python模块 PyPI将其称为progressbar实现这样的功能。如果您不介意添加依赖项,那么这是一个很好的解决方案。否则,请选择其他答案之一。

一个简单的用法示例:

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 install progressbar如果您更喜欢pip。


所有答案都很棒,但是,我最喜欢模块。谢谢大家。
斯坦

8
也许这个例子需要类似的东西bar.start()
Jim Raynor

2
在我的机器开不工作需要添加bar.start()
扎克-

1
该模块已超过2年未更新。不要将其用于新软件!
纳文

4
安装:sudo -H pip install progressbar2
马丁·托马

254

'\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上使用。


7
这比标记的答案更好,因为它也适用于Python 3。
Gerhard Hagerer '16

知道为什么我有时会在一行的末尾得到奇怪的字符,即使我以正在写的字符串为空终止吗?
水库

22
按照编写的方式,代码并未明确说明如何使其适应您要迭代的任何大小(而不是21)。我将让n=21替换range(21)range(n),然后j = (i + 1) / n在循环内添加,然后write用以下稍微修改来替换语句:sys.stdout.write("[%-20s] %d%%" % ('='*int(20*j), 100*j))。现在,您唯一需要做的更改是n=21在循环之前(更可能是n=len(iterable)),然后枚举可迭代对象。我推荐了此编辑,但被拒绝了。功能显然“偏离了帖子的原始意图”。
史蒂文·豪威尔

1
具有n的任意大小的自适应,sys.stdout.write("[{:{}}] {:.1f}%".format("="*i, n-1, (100/(n-1)*i)))仅适用
GabrielChu

3
@ StevenC.Howell为什么不将其作为Mark的答案发布?这是另一个版本,准备工作非常有帮助
GM

91

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


4
tqdm项目正在此处维护由developpers的一个新的团队。
华丽的

1
哇,这个tqdm太神奇了,而且很容易使用:)。
Sidahmed

6
这很容易是最简单的解决方案
kd88 '16

2
它也与Anaconda distrib捆绑在一起!(至少适用于python 3.5及更高版本)
Jacquot

谢谢,令人惊奇,简单而有效
DavideL

23

您可以使用\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()

尝试total10,那么您会收到错误消息ZeroDivisionError: long division or modulo by zero
unseen_rider

19

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

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 %
unseen_rider

6

根据上述答案以及有关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%


进度条对我不显示
unseen_rider

我认为它并不需要很多的小数位,即圆(进度* 100,2)
安德烈斯·桑切斯

4

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

4

使用以下功能进一步改进:

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_bar}s}] {int(100 * j)}%  {postText}")
    sys.stdout.flush()

调用示例:

total=33
for i in range(total):
    printProgressBar(i,total,"blah")
    sleep(0.05)  

输出:

[================================================  ] 96%  blah  

完善!不需要模块
yurividal

3

今天,在尝试了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的内置控制台时,仍然存在断行符。由于这花了我一些时间来弄清楚,因此我想在这里报告这一观察结果。


2

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

2

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

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

'#'是做什么的?
unseen_rider

@unseen_rider这里的“#”只是一个符号,它将随着循环迭代的增加而重复。
NILESH KUMAR

2

最简单的还是

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

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


2

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

1

尝试PyProg。PyProg是Python的开放源代码库,用于创建超级可自定义的进度指示器和栏。

当前版本为1.0.2;它托管在Github上,可在PyPI上使用(下面的链接)。它与Python 3&2兼容,也可以与Qt Console一起使用。

真的很容易使用。如下代码:

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/


1

使用@ Mark-Rushakoff答案,我制定了一种更简单的方法,无需调用sys库。它适用于Python3。在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)

对另一个问题的答案 所述,print是一种精薄包装器,可格式化输入并调用给定对象的写函数。默认情况下,此对象为sys.stdout
史蒂文·霍维尔

0

这是我使用@ 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("")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.