Блог им. 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.5К | ★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:
Фото
Инвестиции без спешки: торгуем в выходные
Алексей Девятов Клиенты Альфа-Инвестиций могут совершать сделки в выходные . Торги в эти дни не отличаются волатильностью, зато на значимые...
Фото
Bitcoin на распутье: минимальный риск против большой коррекции
Биткоин последние несколько дней застрял на уровне поддержки 75000, довольно вяло её тестируя. Однако, если присмотреться, на графике можно...
Фото
Новый терминал для трейдинга: бесплатно весь ноябрь!
Ура! Мы это сделали! Запустили новый софт Live Trader – терминал для объёмного и технического анализа. А теперь хотим, чтобы вы сами попробовали...
Фото
Коротко по дивиденду Диасофта. Глазков на смартлабе. Прогноз на ближайший отчет.
На этой неделе объявлен квартальный дивиденд Диасофта. Много это или мало? Можно ли предсказать из дивиденда финансовые результаты 2 квартала,...

теги блога Albus

....все тэги



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