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)
  • Вопрос задан
  • 2449 просмотров
Решения вопроса 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 или процент в качестве аргумента и выводит в консоль соответствующий прогресс-бар, возвращая каретку в начало строки.
Полагаю, что этих подсказок более, чем достаточно. Дальше попробуйте сами.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
05 апр. 2020, в 12:19
3000 руб./за проект
05 апр. 2020, в 12:11
35000 руб./за проект
05 апр. 2020, в 12:06
5000 руб./за проект