Блог им. Albus

Обработка таймаута на Питоне

    • 03 марта 2020, 13:27
    • |
    • Albus
  • Еще
Коллеги, помогите написать красиво кусочек кода. Обработка ситуации, когда ты заказал котировки с Финама, они не пришли, и ты пробуешь ещё раз. Сейчас я кривенько (чтобы описать задачу) написал так:

try: 
        txt=urlopen(url, timeout=20).readlines()
except timeout:
        print ("Exception!\nWait...")
        sleep (20)
        try:
                txt=urlopen(url, timeout=20).readlines()
        except timeout:
                print ("Exception!\nWait...")
                sleep (20)
                try:
                        txt=urlopen(url, timeout=20).readlines()
                except timeout:
                        print ("Котировки с Финама не пришли")
Как это написать красиво внутри цикла?
10 попыток. Если 10-я неудачная, выводим сообщение
print ("Котировки с Финама не пришли")
2.4К | ★4
23 комментария
def get_data(url, timeout, tries=0, max_tries=10):
  try:
    txt = urlopen(url, timeout=timeout).readlines()
  except TimeoutError:
    print(f«Retry {tries + 1} for {url}»)
    if tries + 1 <= max_tries:
       txt = get_data(url, timeout, tries + 1, max_tries)
    else:
      raise TimeoutError
  return txt
avatar
Михаил, круто! С рекурсией! Я бы так не смог ))))
avatar
Михаил, так вроде тоже можно:



avatar
Albus (Игорь Китаев), можно естественно миллионом способов. Вопрос, как в некотором смысле правильнее для долгосрочной поддержки программы. 

Лучше делить программу на очень небольшие функции.

В Питоне цикл по range обычно признак криво написанной программы.

Создание флагов перед циклом тоже обычно антипатерн. 

Захотите вы потом поменять время ожидания или количество попыток — вам прийдется читать код и менять в нескольких местах. У меня вы просто вызов функции с другими параметрами сделаете.
avatar
Михаил, все отлично

только вот вызывать рекурсивно функцию да еще много раз в exception не очень здорово

Инженер по контролю качества ПО наверняка придерется и не пропустит в продакшн
avatar
_sg_, в питоне цикл с помощью exception реализован — возможно в других языках это и не очень хорошо. 
avatar
Михаил, 
вызывать эту функцию так?
get_data(url, timeout=60, tries=0, max_tries=10)
tries = 0 — уточняю из-за неё потому что она тут глубоко участвует в рекурсии. 
avatar
Albus (Игорь Китаев), при вызове вы передаете url и timeout — остальные параметры не используете get_data(url, 60). 
avatar
Михаил, 
спасибо, работает.
Только с этой строчкой что то не то, я её заменил
    print(f«Retry {tries + 1} for {url}»)
(правильные кавычки "" тоже ставил — безрезультатно)
avatar
Albus (Игорь Китаев), кавычки smartlab автоматически заменяет. f-строки могут не работать на старой версии Питона — у вас какая?
avatar
Михаил, 3.8.2 — самая свежая
avatar
Albus (Игорь Китаев), тогда не знаю — должно работать с 3.6. Дистанционно сложно разобраться. 
avatar
Albus (Игорь Китаев), это самый правильный и читабельный способ, очевидно
avatar
И так сойдёт! Ты же трейдер, а не программист! ))
Eugene Logunov,
не нужно одновременно и false и NULL использовать.
Можно просто done = NULL
исправить while
и убрать
  if (data != NULL) {
    done = TRUE
avatar
рекурсия нужна )
avatar
рекурсию поюзать
avatar

pypi.org/project/retrying/ если хочется прям красиво сделать.

а так в цикле считать попытки и брейкать цикл при удаче.

avatar
day0markets, +1
сделать отдельно функцию запроса которая считывает данные и возвращает сами данные и флаг 1\0 — (есть ошибка получения данных/ нет ошибки)
выглядит на питоне так
for ...
 data, err = LoadData(параметры запроса)
 if err == 0:
   break
 else:
   timeout ()


avatar
sis12qw, ну такое. Имхо, вызывающая функция не должна знать о таймаутах и прочем. Ну и когда потребуется ее дернуть в другом придется лезть и смотреть что она там за флаги возвращает и опять городить огород с retry. Флаги вообще далеко не best practice, лучше exception выбрасывать и его обрабатывть
avatar
def get_data(url, timeout=10, max_tries=10):<br>    data = None<br>    try:<br>        data = urlopen(url, timeout=timeout).readlines()<br>    except TimeoutError:<br>        max_tries -= 1<br>    if data:<br>        return data<br>    if max_tries == 0:<br>        return data<br>    get_data(url, timeout, max_tries)
avatar

Читайте на SMART-LAB:
Фото
Долгосрочное инвестирование умерло. В этот раз - без "но". Хороших новостей не будет
Увеличение капитала посредством инвестирования в доли компаний всегда основывалось на двух тезисах (1) компания сможет на длительном...
Фото
Как на самом деле используют ИИ в алготрейдинге
Если первая часть моего репортажа по конференции алготрейдеров в Москве была об инфраструктуре, то вторая часть будет про искусственный...
«Профи» из группы Займер окупил первый приобретенный портфель
Делимся новостями коллекторского агентства из группы Займер. КА «Профи» вышло на точку окупаемости по первому приобретенному портфелю. ⚡️ Для...
Фото
Ростелеком. МСФО за Q4 2025г. Всё неплохо… но всё равно печально…
Компания Ростелеком опубликовала финансовые результаты за 4 квартал 2025г.: 👉Выручка — 270,5 млрд руб. (+15,6% г/г) 👉Операционные...

теги блога Albus

....все тэги



UPDONW
Новый дизайн