Python Progress Bar - PullRequest
       50

Python Progress Bar

227 голосов
/ 01 июля 2010

Как использовать индикатор выполнения, когда мой скрипт выполняет какое-то задание, которое может занять время?

Например, функция, выполнение которой занимает некоторое время и возвращает True по завершении. Как я могу отображать индикатор выполнения во время выполнения функции?

Обратите внимание, что мне нужно, чтобы это было в режиме реального времени, поэтому я не могу понять, что с этим делать. Нужно ли мне thread для этого? Понятия не имею.

Прямо сейчас я ничего не печатаю во время выполнения функции, однако индикатор выполнения был бы неплох. Также меня больше интересует, как это можно сделать с точки зрения кода.

Ответы [ 27 ]

240 голосов
/ 05 ноября 2014

С помощью tqdm вы можете добавить индикатор прогресса к вашим циклам в секунду:

In [1]: import time

In [2]: from tqdm import tqdm

In [3]: for i in tqdm(range(10)):
   ....:     time.sleep(3)

 60%|██████    | 6/10 [00:18<00:12,  0.33 it/s]

Кроме того, существует графическая версия tqdm, начиная с v2.0.0 (d977a0c):

In [1]: import time

In [2]: from tqdm import tqdm_gui

In [3]: for i in tqdm_gui(range(100)):
  ....:     time.sleep(3)

tqdm gui window

Но будьте осторожны, поскольку tqdm_gui может поднять TqdmExperimentalWarning: GUI is experimental/alpha, вы можете игнорировать его, используя warnings.simplefilter("ignore"), но он будет игнорировать все предупреждения в вашем коде после этого.

152 голосов
/ 01 июля 2010

Существуют определенные библиотеки (, как здесь ), но, возможно, что-то очень простое сделает:

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") # this ends the progress bar

Примечание: progressbar2 - это форк progressbar , который не поддерживался годами.

71 голосов
/ 07 апреля 2013

Приведенные выше предложения довольно хороши, но я думаю, что большинство людей просто хотят получить готовое решение, не зависящее от внешних пакетов, но также пригодное для повторного использования.

Я получил лучшие из всех вышеперечисленных пунктов и превратил их в функцию вместе с контрольными примерами.

Чтобы использовать его, просто скопируйте строки в "def update_progress (progress)"но не тестовый скрипт.Не забудьте импортировать sys.Вызывайте это всякий раз, когда вам нужно отобразить или обновить индикатор выполнения.

Это работает путем прямой отправки символа "\ r" на консоль, чтобы переместить курсор назад к началу.«print» в python не соответствует вышеуказанному символу для этой цели, поэтому нам нужно '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)

Это то, что показывает результат тестового сценария (анимация последнего индикатора выполнения):

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
20 голосов
/ 28 октября 2011

для аналогичного приложения (отслеживание прогресса в цикле) я просто использовал 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
18 голосов
/ 02 мая 2016

Я только что сделал простой класс прогресса для своих нужд после поиска здесь эквивалентного решения.Я подумал, что вполне могу опубликовать это.

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

18 голосов
/ 27 декабря 2015

Этот ответ не зависит от внешних пакетов , я также думаю, что большинству людей просто нужен готовый кусок кода .Приведенный ниже код может быть адаптирован к вашим потребностям путем настройки: символ хода строки '#', столбец size, текст prefix и т. Д.

import sys

def progressbar(it, prefix="", size=60, file=sys.stdout):
    count = len(it)
    def show(j):
        x = int(size*j/count)
        file.write("%s[%s%s] %i/%i\r" % (prefix, "#"*x, "."*(size-x), j, count))
        file.flush()        
    show(0)
    for i, item in enumerate(it):
        yield item
        show(i+1)
    file.write("\n")
    file.flush()

Использование:

import time

for i in progressbar(range(15), "Computing: ", 40):
    time.sleep(0.1) # any calculation you need

Вывод:

Computing: [################........................] 4/15
  • Не требуется второй поток .Некоторые решения / пакеты выше требуют.Второй поток может быть проблемой, например, для jupyter notebook.

  • Работает с любой итерацией , это означает все, что может использоваться на len(),A list, dict, например, ['a', 'b', 'c' ... 'g']

Вы также можете изменить вывод, изменив файл на sys.stderr, например

15 голосов
/ 11 сентября 2014

Попробуйте прогресс от 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
11 голосов
/ 24 августа 2017

Мне нравится Ответ Брайана Хуу за его простоту и отсутствие необходимости во внешних пакетах.Я немного его изменил, поэтому добавляю свою версию здесь:

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%
6 голосов
/ 16 марта 2015

Мне действительно нравится python-progressbar , так как он очень прост в использовании.

Для самого простого случая это просто:

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()])
5 голосов
/ 31 марта 2019

Вы можете использовать tqdm :

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 ]                                                                                                        

Вы можете изменить его и настроить по своему усмотрению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...