[Python] Панель выполнения текста в консоли


Answers

Запись '\ r' вернет курсор к началу строки.

На дисплее отображается процентный счетчик:

import time
import sys

for i in range(100):
    time.sleep(1)
    sys.stdout.write("\r%d%%" % i)
    sys.stdout.flush()
Question

Есть ли хороший способ сделать следующее?

Я написал простое консольное приложение для загрузки и загрузки файлов с FTP-сервера с помощью ftplib.

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

Но я не хочу стирать весь текст, который был напечатан на консоли. (Выполнение «очистить», а затем распечатать обновленный процент.)




я написал простой прогресс:

def bar(total, current, length=10, prefix="", filler="#", space=" ", oncomp="", border="[]", suffix=""):
    if len(border) != 2:
        print("parameter 'border' must include exactly 2 symbols!")
        return None

    print(prefix + border[0] + (filler * int(current / total * length) +
                                      (space * (length - int(current / total * length)))) + border[1], suffix, "\r", end="")
    if total == current:
        if oncomp:
            print(prefix + border[0] + space * int(((length - len(oncomp)) / 2)) +
                  oncomp + space * int(((length - len(oncomp)) / 2)) + border[1], suffix)
        if not oncomp:
            print(prefix + border[0] + (filler * int(current / total * length) +
                                        (space * (length - int(current / total * length)))) + border[1], suffix)

как вы можете видеть, это: длина бара, префикс и суффикс, наполнитель, пробел, текст в баре на 100% (oncomp) и границы

вот пример:

from time import sleep, time
start_time = time()
for i in range(10):
    pref = str((i+1) * 10) + "% "
    complete_text = "done in %s sec" % str(round(time() - start_time))
    sleep(1)
    bar(10, i + 1, length=20, prefix=pref, oncomp=complete_text)

в процессе:

30% [######              ]

полный комплект:

100% [   done in 9 sec   ] 



Запустите это в командной строке Python ( не в среде IDE или в среде разработки):

>>> import threading
>>> for i in range(50+1):
...   threading._sleep(0.5)
...   print "\r%3d" % i, ('='*i)+('-'*(50-i)),

Хорошо работает в моей системе Windows.




Попробуйте библиотеку click написанную Моцартом Питона, Армином Ронахером.

$ pip install click # both 2 and 3 compatible

Чтобы создать простой индикатор выполнения:

import click

with click.progressbar(range(1000000)) as bar:
    for i in bar:
        pass 

Вот как это выглядит:

# [###-------------------------------]    9%  00:01:14

Настройте контент вашего сердца:

import click, sys

with click.progressbar(range(100000), file=sys.stderr, show_pos=True, width=70, bar_template='(_(_)=%(bar)sD(_(_| %(info)s', fill_char='=', empty_char=' ') as bar:
    for i in bar:
        pass

Пользовательский вид:

(_(_)===================================D(_(_| 100000/100000 00:00:02

Есть еще больше вариантов, см. Документы API :

 click.progressbar(iterable=None, length=None, label=None, show_eta=True, show_percent=None, show_pos=False, item_show_func=None, fill_char='#', empty_char='-', bar_template='%(label)s [%(bar)s] %(info)s', info_sep=' ', width=36, file=None, color=None)



Проверьте эту библиотеку: clint

он имеет множество функций, включая индикатор выполнения:

from time import sleep  
from random import random  
from clint.textui import progress  
if __name__ == '__main__':
    for i in progress.bar(range(100)):
        sleep(random() * 0.2)

    for i in progress.dots(range(100)):
        sleep(random() * 0.2)

эта link обеспечивает быстрый обзор ее возможностей




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

Изменить: фиксированная ссылка




import time,sys

for i in range(100+1):
    time.sleep(0.1)
    sys.stdout.write(('='*i)+(''*(100-i))+("\r [ %d"%i+"% ] "))
    sys.stdout.flush()

вывод

[29%] ===================




import sys
def progresssbar():
         for i in range(100):
            time.sleep(1)
            sys.stdout.write("%i\r" % i)

progressbar()

ПРИМЕЧАНИЕ. Если вы запустите это в интерактивном interepter, вы получите лишние цифры, распечатанные




С большими советами выше я разрабатываю индикатор выполнения.

Однако я хотел бы указать на некоторые недостатки

  1. Каждый раз, когда индикатор выполнения очищается, он запускается на новой строке

    print('\r[{0}]{1}%'.format('#' * progress* 10, progress))  
    

    как это:
    [] 0%
    [#] 10%
    [##] 20%
    [###] 30%

2. Квадратная скобка ']', а процентное число справа сдвигается вправо, так как «###» увеличивается.
3. Ошибка, если выражение «progress / 10» не может вернуть целое число.

И следующий код устранит проблему выше.

def update_progress(progress, total):  
    print('\r[{0:10}]{1:>2}%'.format('#' * int(progress * 10 /total), progress), end='')



Прогрессивный модуль модуля python - отличный выбор. Вот мой типичный код:

import time
import progressbar

widgets = [
    ' ', progressbar.Percentage(),
    ' ', progressbar.SimpleProgress(format='(%(value_s)s of %(max_value_s)s)'),
    ' ', progressbar.Bar('>', fill='.'),
    ' ', progressbar.ETA(format_finished='- %(seconds)s  -', format='ETA: %(seconds)s', ),
    ' - ', progressbar.DynamicMessage('loss'),
    ' - ', progressbar.DynamicMessage('error'),
    '                          '
]

bar = progressbar.ProgressBar(redirect_stdout=True, widgets=widgets)
bar.start(100)
for i in range(100):
    time.sleep(0.1)
    bar.update(i + 1, loss=i / 100., error=i)
bar.finish()



Вот мое решение Python 3:

import time
for i in range(100):
    time.sleep(1)
    s = "{}% Complete".format(i)
    print(s,end=len(s) * '\b')

'\ b' - обратная косая черта для каждого символа в вашей строке. Это не работает в окне Windows cmd.




Объединив некоторые из идей, которые я нашел здесь, добавив приблизительное время:

import datetime, sys

start = datetime.datetime.now()

def print_progress_bar (iteration, total):

    process_duration_samples = []
    average_samples = 5

    end = datetime.datetime.now()

    process_duration = end - start

    if len(process_duration_samples) == 0:
        process_duration_samples = [process_duration] * average_samples

    process_duration_samples = process_duration_samples[1:average_samples-1] + [process_duration]
    average_process_duration = sum(process_duration_samples, datetime.timedelta()) / len(process_duration_samples)
    remaining_steps = total - iteration
    remaining_time_estimation = remaining_steps * average_process_duration

    bars_string = int(float(iteration) / float(total) * 20.)
    sys.stdout.write(
        "\r[%-20s] %d%% (%s/%s) Estimated time left: %s" % (
            '='*bars_string, float(iteration) / float(total) * 100,
            iteration,
            total,
            remaining_time_estimation
        ) 
    )
    sys.stdout.flush()
    if iteration + 1 == total:
        print 


# Sample usage

for i in range(0,300):
    print_progress_bar(i, 300)



основанный на вышеупомянутых ответах и ​​других подобных вопросах о шаге прогресса CLI, я думаю, что получил общий общий ответ на все. Проверьте его на https://.com/a/15860757/2254146

Таким образом, код выглядит так:

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()

Выглядит как

Процент: [##########] 99,0%