Python Progress Bar - PullRequest
       57

Python Progress Bar

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

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

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

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

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

Ответы [ 27 ]

4 голосов
/ 02 ноября 2017

Если это большой цикл с фиксированным количеством итераций, занимающий много времени, вы можете использовать эту функцию, которую я сделал. Каждая итерация цикла добавляет прогресс. Где count - это текущая итерация цикла, total - это значение, к которому вы обращаетесь, а size (int) - насколько велика полоса с шагом 10, т.е. (размер 1 = 10 символов, размер 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)
     #do some code 

Выход:

i = 50
>> 050/100 [==========          ]
3 голосов
/ 02 июля 2010

Используйте эту библиотеку: fish ( GitHub ).

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

>>> import fish
>>> while churning:
...     churn_churn()
...     fish.animate()

Веселись!

3 голосов
/ 01 мая 2018

Это довольно просто в Python3:

   import time
   import math

    def show_progress_bar(bar_length, completed, total):
        bar_length_unit_value = (total / bar_length)
        completed_bar_part = math.ceil(completed / bar_length_unit_value)
        progress = "*" * completed_bar_part
        remaining = " " * (bar_length - completed_bar_part)
        percent_done = "%.2f" % ((completed / total) * 100)
        print(f'[{progress}{remaining}] {percent_done}%', end='\r')

    bar_length = 30
    total = 100
    for i in range(0, total + 1):
        show_progress_bar(bar_length, i, total)
        time.sleep(0.1)

    print('\n')
2 голосов
/ 24 октября 2018

При работе в ноутбуках jupyter использование обычного tqdm не работает, так как записывает вывод в несколько строк. Используйте это вместо:

import time
from tqdm import tqdm_notebook as tqdm

for i in tqdm(range(100))
    time.sleep(0.5)
2 голосов
/ 12 марта 2018

Приведенный ниже код является довольно общим решением, а также имеет оценку времени, прошедшего и оставшегося времени. Вы можете использовать любую итерацию с ним. Индикатор выполнения имеет фиксированный размер 25 символов, но он может отображать обновления с шагом 1%, используя символы полного, половины и четверти блока. Вывод выглядит так:

 18% |████▌                    | [0:00:01, 0:00:07]

Код с примером:

import sys, time
from numpy import linspace

def ProgressBar(iterObj, refreshTime=10):
  #refreshTime=10: refresh the time estimate at least every 10 sec.
  def SecToStr(sec):
    m, s = divmod(sec, 60)
    h, m = divmod(m,   60)
    return u'%d:%02d:%02d'%(h,m,s)
  L       = len(iterObj)
  steps   = {int(x):y for x,y in zip(np.linspace(0,L,  min(100,L),endpoint=False), 
                                     np.linspace(0,100,min(100,L),endpoint=False))}
  qSteps  = ['', u'\u258E',u'\u258C',u'\u258A'] # quarter and half block chars
  startT  = endT = time.time()
  timeStr = ' [0:00:00, -:--:--]'
  for nn,item in enumerate(iterObj):
    if nn in steps:
      done    = u'\u2588'*int(steps[nn]/4.0)+qSteps[int(steps[nn]%4)]
      todo    = ' '*(25-len(done))
      barStr  = u'%4d%% |%s%s|'%(steps[nn], done, todo)
      if nn>0:
        endT    = time.time()
        timeStr = ' [%s, %s]'%(SecToStr(endT-startT), SecToStr((endT-startT)*(L/float(nn)-1)))
      sys.stdout.write('\r'+barStr+timeStr); sys.stdout.flush()
    elif time.time()-endT > refreshTime:
      endT    = time.time()
      timeStr = ' [%s, %s]'%(SecToStr(endT-startT), SecToStr((endT-startT)*(L/float(nn)-1)))
      sys.stdout.write('\r'+barStr+timeStr); sys.stdout.flush()
    yield item
  barStr  = u'%4d%% |%s|'%(100, u'\u2588'*25)
  timeStr = ' [%s, 0:00:00]\n'%(SecToStr(time.time()-startT))
  sys.stdout.write('\r'+barStr+timeStr); sys.stdout.flush()

# Example
s = ''
for op in ProgressBar(list('Disassemble and reassemble this string')):
  time.sleep(0.5)
  s += op
print s

Предложения по улучшению или другие комментарии приветствуются. Веселитесь.

2 голосов
/ 11 февраля 2015

Мне нравится page .

Начинается с простого примера и переходит на многопоточную версию.Работает из коробки.Пакеты сторонних разработчиков не требуются.

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

import time
import sys

def do_task():
    time.sleep(1)

def example_1(n):
    for i in range(n):
        do_task()
        print '\b.',
        sys.stdout.flush()
    print ' Done!'

print 'Starting ',
example_1(10)

Или вот пример использования потоков для запуска вращающейся панели загрузки во время работы программы:

import sys
import time
import threading

class progress_bar_loading(threading.Thread):

    def run(self):
            global stop
            global kill
            print 'Loading....  ',
            sys.stdout.flush()
            i = 0
            while stop != True:
                    if (i%4) == 0: 
                        sys.stdout.write('\b/')
                    elif (i%4) == 1: 
                        sys.stdout.write('\b-')
                    elif (i%4) == 2: 
                        sys.stdout.write('\b\\')
                    elif (i%4) == 3: 
                        sys.stdout.write('\b|')

                    sys.stdout.flush()
                    time.sleep(0.2)
                    i+=1

            if kill == True: 
                print '\b\b\b\b ABORT!',
            else: 
                print '\b\b done!',


kill = False      
stop = False
p = progress_bar_loading()
p.start()

try:
    #anything you want to run. 
    time.sleep(1)
    stop = True
except KeyboardInterrupt or EOFError:
         kill = True
         stop = True
1 голос
/ 04 февраля 2018

Попробуйте PyProg. PyProg - это библиотека с открытым исходным кодом для Python, позволяющая создавать супер настраиваемые индикаторы и индикаторы выполнения.

В настоящее время версия 1.0.2; он размещен на Github и доступен на PyPI (ссылки внизу). Он совместим с Python 3 и 2, а также может использоваться с Qt Console.

Это действительно удобно. Следующий код:

import pyprog
from time import sleep

# Create Object
prog = pyprog.ProgressBar(" ", "", 34)
# 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()

даст:

Initial State:
Progress: 0% --------------------------------------------------

When half done:
Progress: 50% #########################-------------------------

Final State:
Progress: 100% ##################################################

Я действительно сделал PyProg, потому что мне нужна простая, но супер настраиваемая библиотека индикатора выполнения. Вы можете легко установить его с помощью: pip install pyprog.

PyProg Github: https://github.com/Bill13579/pyprog
PyPI: https://pypi.python.org/pypi/pyprog/

1 голос
/ 22 октября 2017

Мне нравится Габриэль ответ, но я изменил его, чтобы сделать его более гибким. Вы можете отправить длину строки в функцию и получить индикатор выполнения с любой длиной, которую вы хотите. И вы не можете иметь индикатор выполнения с нулевой или отрицательной длиной. Также вы можете использовать эту функцию как Габриэль ответ (см. Пример № 2).

import sys
import time

def ProgressBar(Total, Progress, BarLength=20, ProgressIcon="#", BarIcon="-"):
    try:
        # You can't have a progress bar with zero or negative length.
        if BarLength <1:
            BarLength = 20
        # Use status variable for going to the next line after progress completion.
        Status = ""
        # Calcuting progress between 0 and 1 for percentage.
        Progress = float(Progress) / float(Total)
        # Doing this conditions at final progressing.
        if Progress >= 1.:
            Progress = 1
            Status = "\r\n"    # Going to the next line
        # Calculating how many places should be filled
        Block = int(round(BarLength * Progress))
        # Show this
        Bar = "[{}] {:.0f}% {}".format(ProgressIcon * Block + BarIcon * (BarLength - Block), round(Progress * 100, 0), Status)
        return Bar
    except:
        return "ERROR"

def ShowBar(Bar):
    sys.stdout.write(Bar)
    sys.stdout.flush()

if __name__ == '__main__':
    print("This is a simple progress bar.\n")

    # Example #1:
    print('Example #1')
    Runs = 10
    for i in range(Runs + 1):
        progressBar = "\rProgress: " + ProgressBar(10, i, Runs)
        ShowBar(progressBar)
        time.sleep(1)

    # Example #2:
    print('\nExample #2')
    Runs = 10
    for i in range(Runs + 1):
        progressBar = "\rProgress: " + ProgressBar(10, i, 20, '|', '.')
        ShowBar(progressBar)
        time.sleep(1)

    print('\nDone.')

# Example #2:
Runs = 10
for i in range(Runs + 1):
    ProgressBar(10, i)
    time.sleep(1)

Результат:

Это простой индикатор выполнения.

Пример # 1

Прогресс: [### -------] 30%

Пример # 2

Прогресс: [|||||||||||| ........] 60%

Готово.

1 голос
/ 01 июля 2010

Если ваша работа не может быть разбита на измеримые куски, вы можете вызвать вашу функцию в новом потоке и указать время, которое потребуется:

import thread
import time
import sys

def work():
    time.sleep( 5 )

def locked_call( func, lock ):
    lock.acquire()
    func()
    lock.release()

lock = thread.allocate_lock()
thread.start_new_thread( locked_call, ( work, lock, ) )

# This part is icky...
while( not lock.locked() ):
    time.sleep( 0.1 )

while( lock.locked() ):
    sys.stdout.write( "*" )
    sys.stdout.flush()
    time.sleep( 1 )
print "\nWork Done"

Вы, очевидно, можете увеличить точность синхронизации по мере необходимости.

1 голос
/ 31 декабря 2015

Вот краткое решение, которое программно строит полосу загрузки (вы должны решить, как долго вы этого хотите).

import time

n = 33  # or however many loading slots you want to have
load = 0.01  # artificial loading time!
loading = '.' * n  # for strings, * is the repeat operator

for i in range(n+1):
    # this loop replaces each dot with a hash!
    print('\r%s Loading at %3d percent!' % (loading, i*100/n), end='')
    loading = loading[:i] + '#' + loading[i+1:]
    time.sleep(load)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...