5

Прогресс-бар в Python

22

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

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

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

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

5 ответ(ов)

1

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

Я собрал лучшие идеи из предложенных ранее и оформил их в виде функции, а также добавил тестовые случаи для демонстрации.

Чтобы использовать эту функцию, просто скопируйте строки под заголовком 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(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

Надеюсь, это будет полезно!

0

Для использования библиотеки progress с PyPI, вы можете следовать приведенному ниже примеру. Эта библиотека позволяет легко создавать графические индикаторы прогресса в вашем проекте на Python.

Вот пример кода:

from progress.bar import Bar

bar = Bar('Processing', max=20)
for i in range(20):
    # Здесь вы можете выполнять какую-то работу
    bar.next()
bar.finish()

Когда вы выполните этот код, вы получите индикатор прогресса, который будет выглядеть, например, так:

Processing |#############                   | 42/100

Этот простейший пример создает индикатор, который отображает процесс выполнения цикла с 20 итерациями. Не забудьте установить библиотеку progress, если она у вас еще не установлена:

pip install progress

Таким образом, вы можете легко отслеживать прогресс выполнения задач в вашей программе!

0

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

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 range(progress.total):
    progress.current += 1
    progress()
    sleep(0.1)
progress.done()

Этот код выведет следующее сообщение:

[======== ] 17/80 ( 21%) 63 to go

Вы можете настроить параметры класса ProgressBar, такие как width, symbol и форматирование. Этот класс удобно использовать в циклах, чтобы визуализировать процесс выполнения задач.

0

Чтобы отобразить прогресс выполнения в виде графической полосы или процентного индикатора, можно использовать форматирование строки и специальный символ возврата каретки \r. Вот как это сделать на Python:

Простой пример с полосой прогресса

K = 628318
for k in range(K):
    # Здесь ваша логика
    print(end="\r|%-80s|" % ("="*(80*(k+1)//K)))

Кроме того, можно добавить завершающий print() в конце, чтобы перейти на новую строку:

|=====================================================================       |

Удобная функция для имитации tqdm

Если хотите сделать более удобный и переиспользуемый подход, вы можете создать функцию-генератор:

def progbar(iterobj):
    K = len(iterobj)
    for k, obj in enumerate(iterobj):
        print(end="\r|%-80s|" % ("="*(80*(k+1)//K)))
        yield obj
    print()  # Переход на новую строку после завершения
    raise StopIteration

for k in progbar(range(628318)):
    # Здесь ваша логика
    pass

Процентный индикатор прогресса

Также, можно отображать процент выполнения:

K = 628318
for k in range(K):
    # Здесь ваша логика
    print(end=f"\r{(k+1)/K*100:6.2f} %")

Результат будет выглядеть так:

 94.53 %

Комбинирование обоих подходов

Не сложно комбинировать оба подхода — индикатор прогресса и процентный индикатор. Основные моменты — это использование символа возврата каретки \r и подавление стандартного end="\n" в функции print().

В итоге, вы можете настроить отображение прогресса так, как вам нужно!

0

Если у вас есть большой цикл с фиксированным количеством итераций, который занимает много времени, вы можете использовать эту функцию, которую я написал. Каждая итерация цикла увеличивает прогресс. Параметр count — это текущая итерация цикла, total — это общее количество итераций, а size(int) — это размер прогресс-бара в increments of 10, то есть (size 1 = 10 символов, size 2 = 20 символов).

import sys

def loadingBar(count, total, size):
    percent = float(count) / float(total) * 100
    sys.stdout.write("\r" + str(int(count)).rjust(3, '0') + "/" + str(int(total)).rjust(3, '0') + ' [' + '=' * int(percent / 10) * size + ' ' * (10 - int(percent / 10)) * size + ']')

Пример использования:

for i in range(0, 100):
    loadingBar(i, 100, 2)
    # выполняем некоторый код

Вывод:

i = 50
>> 050/100 [==========          ]

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь