ivan_suroegin
@ivan_suroegin
Интернет-маркетолог, программист

Правильное отображение прогрессбара на Python — что не так?

Добрый вечер!

Подскажите, пожалуйста, не могу понять почему неверно отображается прогрессбар?
Мне бы хотелось получить так, чтобы скорость возрастания процентного значения и заполнения прогрессбара соответствовала количеству строк в списке li.

Буду рад вашим объяснениям!
Спасибо, с уважением,
Иван.

import requests
import time
import random
import sys

li = ["25min", "tester", "testsetset"]

status404 = []
status200 = []
lenLi = len(li) + 1
def wait():
    time.sleep(random.randint(2,3))

for x in li:
	
	link = "https://vk.com" + x
	q = requests.get(link)
	stat = q.status_code
	if 200 != stat:
		status404.append(x.rstrip())
		wait()
	else:
		status200.append(x.rstrip())
		wait()
	for i in range(lenLi):
		sys.stdout.write('\r')
		sys.stdout.write("[%-30s] %d%%" % ('='*i, i))
		sys.stdout.flush()

print("404 status")
for i in status404:
	print(i)
print("\n- - - - -\n200 status:")
for i in status200:
        print(i)
  • Вопрос задан
  • 2792 просмотра
Решения вопроса 1
Kademn
@Kademn
Злой
Давайте по-порядку.
Вот участок кода, отвечающий за прогресс-бар:
for i in range(lenLi):
    sys.stdout.write('\r')
    sys.stdout.write("[%-30s] %d%%" % ('='*i, i))
    sys.stdout.flush()

Во-первых вывод в консоль у вас неправильный. Длина вашего прогресс-бара 30 символов. Значит при каждой итерации нужно выводить количество символов, соответствующее итерации, не забывая, что нельзя выводить дробное количество символов. К примеру, если длина списка у вас 5, значит 30/5=6 символов добавляет каждая итерация цикла. Но вы переписываете весь прогресс-бар, поэтому можно посчитать "часть" от всей длины (30 символов) для этого шага. Например для длины 5, шаг 1 - это 1/5 длины, шаг 2 это 2/5 длины и т.д. Тогда количество символов это количество символов для "полной" длины умножить на полученную часть.
part = float(i)/(lenLi-1)
symbols_num = int(30 * part)

lenLi -1, так как выше вы увеличивали длину на единицу (видимо для range), то тогда range стоило бы начинать с 1, а не с нуля. А проценты легко получить умножив part на 100, не забыв сменить форматирование вывода с '%s%%' на, скажем, '%3.2f%%', так как в выводе дробное число и оно очень плохо смотрится, если %s.
Теперь прогресс-бар будет выводиться правильно:
for i in range(1, lenLi):
    sys.stdout.write('\r')
    part = float(i)/(lenLi-1)
    symbols_num = int(30 * part)
    sys.stdout.write("[%-30s] %3.2f%%" % ('='*symbols_num, part*100))
    sys.stdout.flush()

Правда, чтобы успеть увидеть изменения, добавьте в цикл wait(), иначе все 100% заполнятся за доли секунды.
UPD
Да, вы для каждой ссылки заполняете прогресс-бар от нуля до 100 процентов. Цикл внутри цикла не нужен. Прогресс-бар должен быть частью for x in li:. Но, для правильного отображения прогресс-бара, вам необходимо считать номер шага. Для это можно либо завести переменную, которая будет считать шаги, либо использовать функцию enumerate:
for step_number, x in enumerate(li):
Учитывая, что вам удобнее нумеровать шаги с единицы, правильнее было бы использовать
for step_number, x in enumerate(li, 1):
А вообще, если вы хотите использовать прогресс-бар и в других местах кода, то стоило бы завести отдельную функцию для печати прогресса, которая принимает дробное число от 0 до 1 или процент в качестве аргумента и выводит в консоль соответствующий прогресс-бар, возвращая каретку в начало строки.
Полагаю, что этих подсказок более, чем достаточно. Дальше попробуйте сами.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы