持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
介绍
我们在开发程序时,尤其是涉及到网络请求的情况下,比如爬虫的程序,会高频率的涉及到网络请求,但是常常会出现因为各种原因而请求失败的情况,就需要不断的重试请求,这种情况下,就可以用到retry 来帮助我们优雅的进行重试操作了。
安装和使用
安装
pip install retry
使用
retry
retry 本质上就是一个装饰器,通过装饰器的不同参数来控制重试某一段函数的执行方式,因此我们首先需要知道retry 都有哪些参数,以及这些参数表示的意思。
def retry(exceptions=Exception, tries=-1, delay=0, max_delay=None, backoff=1, jitter=0, logger=logging_logger):
"""Return a retry decorator.
:param exceptions: 一个异常类型,或者是能够捕获到的异常类型的元组,默认是Exception.
:param tries: 最大尝试次数,默认是-1表示重试无限次。
:param delay: 每次重试之间的时间间隔,默认是0即没有时间间隔
:param max_delay: 每次重试之间最大的时间间隔,默认值无,即没有限制
:param backoff: 下次重试是上次重试时间间隔的多少倍,默认是1,即每次重试时间间隔相同
:param jitter: 每次重试时间间隔增加多少时长,默认是0, 如果提供的参数是一个元组,那么增加的时长就是元组中的随机数。
:param logger: 在尝试失败时调用retry的日志模块,如果为None,则不记录
"""
下面我们就用代码示例进行简单演示:
from retry import retry
@retry()
def make_trouble():
"""
Retry until succeed
:return:
"""
print("重试直到代码成功")
@retry(ZeroDivisionError, tries=3, delay=2)
def make_trouble():
'''当出现ZeroDivisionError异常时,进行3次重试,每次充实之间的时间间隔是2s'''
@retry((ValueError, TypeError), delay=1, backoff=2)
def make_trouble():
'''当出现ValueError or TypeError时,每次重试时间间隔都是上一次重试时间间隔的2倍'''
@retry((ValueError, TypeError), delay=1, backoff=2, max_delay=4)
def make_trouble():
'''当出现ValueError or TypeError时,每次重试时间间隔都是上一次重试时间间隔的2倍,但是由于限制了最大时间间隔的参数,因此时间间隔变为1 2 4 4 ....'''
@retry(ValueError, delay=1, jitter=1)
def make_trouble():
'''当出现ValueError时, 每次重试的时间间隔都是上一次重试时间间隔+1,即1 2 3 4....'''
当然上面的代码默认我们都开启了日式记录,如果需要查看具体日志,我们可以通过下面的方式进行日志查看:
if __name__ == '__main__':
import logging
logging.basicConfig() # 将日志打印到终端
make_trouble()
retry_call
除了可以使用retry装饰器之外,如果函数执行失败并且需要重复执行的时候,我们也可以使用retry_call,该方法和装饰器非常类似,但是该方法可以接受函数和函数参数作为该方法的参数,可以动态的调整函数重试时的参数,比retry更加灵活。
首先来看一下该方法的详细使用方式:
def retry_call(f, fargs=None, fkwargs=None, exceptions=Exception, tries=-1, delay=0, max_delay=None, backoff=1,
jitter=0,
logger=logging_logger):
"""
当函数执行失败时重新调用函数.
:param f: 需要被执行的函数.
:param fargs: 执行函数的位置参数.
:param fkwargs: 执行函数的关键字参数.
:param exceptions: 异常类型,可以是一个类型也可以是一个元组.
:其他参数参考retry装饰器
:returns: 执行函数的返回值.
"""
知道了该方法的参数,就简单的看一下代码示例:
import requests
from retry.api import retry_call
def make_trouble(service, info=None):
if not info:
info = ''
r = requests.get(service + info)
return r.text
def what_is_my_ip(approach=None):
if approach == "optimistic":
tries = 1
elif approach == "conservative":
tries = 3
else:
# skeptical
tries = -1
result = retry_call(make_trouble, fargs=["http://ipinfo.io/"], fkwargs={"info": "ip"}, tries=tries)
print(result)
what_is_my_ip("conservative")
总结
当我们清楚的知道我们的代码可能会出现未知的异常时,为了更加方便的执行代码灵活的使用retry 模块会使开发效率更高,至于使用retry 还是 retry_call 就根据实际代码情况选择即可。