Прогресс-бар в Python
Как я могу использовать индикатор прогресса, когда мой скрипт выполняет задачу, на выполнение которой может уйти время?
Например, у меня есть функция, выполнение которой занимает некоторое время и которая возвращает True
, когда задача завершена. Как я могу отобразить индикатор прогресса на протяжении всей работы этой функции?
Обратите внимание, что мне нужно, чтобы это происходило в реальном времени, и я не могу понять, как это реализовать. Мне нужен отдельный поток для этого? Я не уверен.
На данный момент я не вывожу ничего в консоль во время выполнения функции, однако наличие индикатора прогресса было бы полезным. Меня больше интересует, как это можно реализовать с точки зрения кода.
5 ответ(ов)
Ответ на ваш вопрос очень простой, и вы правы — многие пользователи предпочитают готовые решения без зависимости от внешних библиотек, которые также легко переиспользовать.
Я собрал лучшие идеи из предложенных ранее и оформил их в виде функции, а также добавил тестовые случаи для демонстрации.
Чтобы использовать эту функцию, просто скопируйте строки под заголовком 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
Надеюсь, это будет полезно!
Для использования библиотеки 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
Таким образом, вы можете легко отслеживать прогресс выполнения задач в вашей программе!
Вы можете использовать этот простой класс 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
и форматирование. Этот класс удобно использовать в циклах, чтобы визуализировать процесс выполнения задач.
Чтобы отобразить прогресс выполнения в виде графической полосы или процентного индикатора, можно использовать форматирование строки и специальный символ возврата каретки \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()
.
В итоге, вы можете настроить отображение прогресса так, как вам нужно!
Если у вас есть большой цикл с фиксированным количеством итераций, который занимает много времени, вы можете использовать эту функцию, которую я написал. Каждая итерация цикла увеличивает прогресс. Параметр 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 [========== ]
Эта функция обновляет строку на одной и той же строке терминала, что позволяет визуально отслеживать прогресс выполнения операции без переноса на новую строку.
Как изменить порядок столбцов в DataFrame?
'pip' не распознан как командa внутреннего или внешнего формата
Почему statistics.mean() работает так медленно?
Преобразование строки даты JSON в datetime в Python
Есть ли разница между поднятием экземпляра класса Exception и самого класса Exception?