Вопрос-Ответ

Python Progress Bar

Индикатор выполнения Python

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

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

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

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

Переведено автоматически
Ответ 1

С помощью tqdm (conda install tqdm или pip install tqdm) вы можете добавить индикатор выполнения в свои циклы за секунду:

from time import sleep
from tqdm import tqdm
for i in tqdm(range(10)):
sleep(3)

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

Также существует версия для ноутбука:

from tqdm.notebook import tqdm
for i in tqdm(range(100)):
sleep(3)

Вы можете использовать tqdm.auto вместо tqdm.notebook для работы как в терминале, так и в ноутбуках.

tqdm.contrib содержит несколько вспомогательных функций для выполнения таких действий, как enumerate, map и zip. В tqdm.contrib.concurrent есть параллельные отображения.

Вы даже можете отправлять прогресс на свой телефон после отключения от ноутбука jupyter с помощью tqdm.contrib.telegram или tqdm.contrib.discord.

GIF-файл, показывающий пример вывода файла tqdm.contrib.telegram для отображения индикатора выполнения в мобильном приложении Telegram

Ответ 2

Используйте alive-progress, самый крутой индикатор выполнения из когда-либо существовавших! Просто pip install alive-progress и готово!

GIF, показывающий пример alive-прогресса

Чтобы эффективно использовать любой индикатор выполнения, т. Е. Получать как процент завершения, так и ETA, вы должны иметь возможность указывать общее количество элементов. Затем alive-progress будет отслеживать, где в данный момент находится ваша обработка и сколько времени это займет!
Не волнуйтесь, если вы не сможете оценить общее количество, alive-progress все равно будет работать.

Чтобы использовать его, вы можете либо управлять alive-progress' bar напрямую:

def compute():
with alive_bar(1000) as bar: # your expected total
for item in items: # the original loop
print(item) # your actual processing here
bar() # call `bar()` at the end


compute()

Or, if you prefer to keep the codes isolated, just insert a yield in your processing code (to mark when an item has been processed), then drive the alive-progress' bar like this:

def compute():
for item in items:
print(item)
yield # simply insert this :)


with alive_bar(1000) as bar:
for i in compute():
bar()

Either way, you'll get an awesome and animated progress bar!

|█████████████▎                      | ▅▃▁ 321/1000 [32%] in 8s (40.1/s, eta: 16s)

And it supports a LOT OF advanced options right out of the box!!
some advanced options

Disclosure: I'm the proud author of alive-progress, which has 5K+ ⭐️ on github!

Read the documentation at https://github.com/rsalmei/alive-progress to get to know all the advanced features.

Посмотрите еще несколько анимаций, которые он может выполнять как в виджетах spinner, так и в bar: GIF, показывающий различные стили выполнения alive-progress

Это также работает на ноутбуках Jupyter! GIF, показывающий живой прогресс в ноутбуках Jupyter

Вы даже можете создавать свои собственные анимации!! GIF, показывающий дизайнера анимации

Ответ 3

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

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 range(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, который не поддерживался годами.

Ответ 4

Никаких внешних пакетов. Готовый фрагмент кода.

Вы можете настроить символ выполнения в строке "#", строку size, текст prefix и т.д.

Python 3.6+ (f-строка) с оценкой оставшегося времени

import sys
import time

def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.6+
count = len(it)
start = time.time()
def show(j):
x = int(size*j/count)
remaining = ((time.time() - start) / j) * (count - j)

mins, sec = divmod(remaining, 60)
time_str = f"{int(mins):02}:{sec:05.2f}"

print(f"{prefix}[{u'█'*x}{('.'*(size-x))}] {j}/{count} Est wait {time_str}", end='\r', file=out, flush=True)

for i, item in enumerate(it):
yield item
show(i+1)
print("\n", flush=True, file=out)
[████████████████████████████.........................] 24/50 Est wait 00:05.38

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

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

введите описание изображения здесь



  • Не требует второго потока. Для некоторых решений / пакетов, описанных выше, требуется.



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



  • Работает с генераторами, нужно только обернуть его списком (). Например, for i in progressbar(list(your_generator), "Computing: ", 40): если работа не выполняется в генераторе. В этом случае вам нужно другое решение (например, tqdm).



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


Python 3.3+

import sys
def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.3+
count = len(it)
def show(j):
x = int(size*j/count)
print("{}[{}{}] {}/{}".format(prefix, "#"*x, "."*(size-x), j, count),
end='\r', file=out, flush=True)
show(0)
for i, item in enumerate(it):
yield item
show(i+1)
print("\n", flush=True, file=out)

Python 2 (старый код)

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