Albus
Albus личный блог
03 марта 2020, 13:27

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

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

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 ("Котировки с Финама не пришли")
23 Комментария
  • Михаил
    03 марта 2020, 13:46
    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
      • Михаил
        03 марта 2020, 14:10
        Albus (Игорь Китаев), можно естественно миллионом способов. Вопрос, как в некотором смысле правильнее для долгосрочной поддержки программы. 

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

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

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

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

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

          Инженер по контролю качества ПО наверняка придерется и не пропустит в продакшн
          • Михаил
            03 марта 2020, 14:51
            _sg_, в питоне цикл с помощью exception реализован — возможно в других языках это и не очень хорошо. 
          • Михаил
            03 марта 2020, 14:53
            Albus (Игорь Китаев), при вызове вы передаете url и timeout — остальные параметры не используете get_data(url, 60). 
          • Михаил
            03 марта 2020, 16:13
            Albus (Игорь Китаев), кавычки smartlab автоматически заменяет. f-строки могут не работать на старой версии Питона — у вас какая?
              • Михаил
                03 марта 2020, 16:30
                Albus (Игорь Китаев), тогда не знаю — должно работать с 3.6. Дистанционно сложно разобраться. 
      • _xXx_
        03 марта 2020, 15:28
        Albus (Игорь Китаев), это самый правильный и читабельный способ, очевидно
  • Пафос Респектыч
    03 марта 2020, 13:47
    И так сойдёт! Ты же трейдер, а не программист! ))
  • siesta00
    03 марта 2020, 13:59
    рекурсия нужна )
  • tashik
    03 марта 2020, 14:01
    рекурсию поюзать
  • day0markets.ru
    03 марта 2020, 15:28

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

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

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


      • day0markets.ru
        04 марта 2020, 06:57
        sis12qw, ну такое. Имхо, вызывающая функция не должна знать о таймаутах и прочем. Ну и когда потребуется ее дернуть в другом придется лезть и смотреть что она там за флаги возвращает и опять городить огород с retry. Флаги вообще далеко не best practice, лучше exception выбрасывать и его обрабатывть
  • Сергей
    04 марта 2020, 17:36
    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)
    

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн