Как сделать еще прогресс в python?
Мне нужно создать индикатор выполнения на Python, который будет распечатан на x%
.
Так, например, если значение составляет 62%, есть ли способ, чтобы он мог распечатать что-то вроде этого?
▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯ 62%
Или, например, 23%
▮▮▮▮▮▮▮▮▮▮▮▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯ 23%
Ответы
Ответ 1
Чистое решение с использованием параметра end
print()
:
Оператор print()
позволяет указать, какие последние chars
будут напечатаны в конце вызова. По умолчанию для параметра end
установлено значение '\r\n'
, которое является возвратом каретки и новой линией. Это перемещает "курсор" в начало следующей строки, чего вы хотели бы в большинстве случаев.
Однако для индикатора выполнения вы хотите иметь возможность распечатывать обратно по панели, чтобы вы могли изменить текущую позицию и процент, без конечного результата, выглядящего плохо на нескольких строках.
Для этого нам нужно установить параметр end
только для возврата каретки: '\r'
. Это вернет нашу текущую позицию в начало строки, чтобы мы могли re-print
на индикаторе выполнения.
Как демонстрация того, как это может работать, я сделал этот простой маленький код, который увеличит индикатор выполнения на 1%
каждые 0.5
секунды. Ключевой частью кода является оператор print
, так что это часть, которую вы, вероятно, уберете и поместите в свой основной script.
import time, math
bl = 50 #the length of the bar
for p in range(101):
chars = math.ceil(p * (bl/100))
print('▮' * chars + '▯' * (bl-chars), str(p) + '%', end='\r')
time.sleep(0.5)
(nb используемые здесь символы будут скопированы из вашего вопроса ( "▮, ▯" ), и для меня они не печатались на консоли, и в этом случае вам нужно будет заменить их на другие: "█" и '')
Этот код делает то, что вы хотите, и постоянно увеличивает процент, вот пример того, как он будет выглядеть, когда p = 42
:
▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯ 42%
Ответ 2
Основываясь на вашем вопросе и Ответ Джо Иддона, я сделал еще один шаг, основываясь на своем понимании от возиться с tqdm. Как отметил Irmen de Jong, если вы не против использовать библиотеку для этого tqdm, это классно.
Панель прогресса с градиентными блоками + обновление масштабирования терминала (python 3.3 +)
Это примерное решение, если вы хотите создать его с нуля (будет работать на Python 3.3+ для более ранних версий):
import os
import time
# This will only work for python 3.3+ due to use of
# os.get_terminal_size the print function etc.
FULL_BLOCK = '█'
# this is a gradient of incompleteness
INCOMPLETE_BLOCK_GRAD = ['░', '▒', '▓']
def progress_percentage(perc, width=None):
assert(isinstance(perc, float))
assert(0. <= perc <= 100.)
# if width unset use full terminal
if width is None:
width = os.get_terminal_size().columns
# progress bar is block_widget separator perc_widget : ####### 30%
max_perc_widget = '[100.00%]' # 100% is max
separator = ' '
blocks_widget_width = width - len(separator) - len(max_perc_widget)
assert(blocks_widget_width >= 10) # not very meaningful if not
perc_per_block = 100.0/blocks_widget_width
# epsilon is the sensitivity of rendering a gradient block
epsilon = 1e-6
# number of blocks that should be represented as complete
full_blocks = int((perc + epsilon)/perc_per_block)
# the rest are "incomplete"
empty_blocks = blocks_widget_width - full_blocks
# build blocks widget
blocks_widget = ([FULL_BLOCK] * full_blocks)
blocks_widget.extend([INCOMPLETE_BLOCK_GRAD[0]] * empty_blocks)
# marginal case - remainder due to how granular our blocks are
remainder = perc - full_blocks*perc_per_block
# epsilon needed for rounding errors (check would be != 0.)
# based on reminder modify first empty block shading
# depending on remainder
if remainder > epsilon:
grad_index = int((len(INCOMPLETE_BLOCK_GRAD) * remainder)/perc_per_block)
blocks_widget[full_blocks] = INCOMPLETE_BLOCK_GRAD[grad_index]
# build perc widget
str_perc = '%.2f' % perc
# -1 because the percentage sign is not included
perc_widget = '[%s%%]' % str_perc.ljust(len(max_perc_widget) - 3)
# form progressbar
progress_bar = '%s%s%s' % (''.join(blocks_widget), separator, perc_widget)
# return progressbar as string
return ''.join(progress_bar)
def test_pbar(width=None):
import random
random.seed(42)
i = 0
while(i < 10000):
print(progress_percentage(i/100, width=width), end='\r')
time.sleep(0.25)
i += random.randrange(3000)
print(progress_percentage(100.00, width=width), end='\r')
print('\nDone!')
if __name__ == "__main__":
print('=== First test with width = 20 ===')
test_pbar(width=20)
print('=== Now with terminal width ===')
test_pbar(width=None)
Вот как должен выглядеть вывод при запуске с различными размерами терминалов (tmux panes):
![Выполняется код в разных размерах терминала (tmux panes)]()
Ответ 3
Я всегда нашел tqdm
библиотеку, очень удобную для этого. Он маленький, имеет низкие накладные расходы и очень прост в использовании: просто обертывание итерации часто делает работу уже.
Пример
from tqdm import tqdm
for i in tqdm(range(10000)):
...