小屌丝:鱼哥,最近python的文章写的有点少了!
小鱼:也不算少,只是最近大部分精力都放在全链路压测专栏的文章。
小屌丝:你这全链路压测没拦着你写,但是python文章也不能不更新啊。
小鱼:我凸(艹皿艹 )~ ~ 天天凌晨两点半才去睡觉了,还想我啥时候睡觉…
小屌丝:睡觉归睡觉,但是python文章不能不更新啊。
小鱼:我屮艸芔茻~ ~ 我白天上班,还得加加班,晚上10:30 ~ 凌晨2:30 才有时间写文章,你这是压榨! !
小屌丝:我这是为了妹子~ ~
小鱼:别那妹子做挡箭牌,快说吧,今天遇到啥问题了?
小屌丝:…说实话,最近有个妹子问我,异常有哪些写法!
小鱼:这个问题,问的很好。
关于异常的写法,小鱼最近在面试官的时候,也会经常问到求职者。
但是回答的,有点…不完整吧…
其实关于异常的写法,小鱼整理过一篇《常用断言及异常处理》,只是当时是在编写Web端自动化框架时,整理的,
那篇博文,更多的是python自带的库。
而今天我们要来介绍的,是第三方库–retrying!
我们在通过日志输出,来定位异常是很常见的一种,
例如:
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 def do_something(): pass def log_error(): pass try: do_something() except: log_error()
这个写法,也是简单版的异常写法
增加重试次数,也就是说第一次请求失败,再次发起请求,直到请求成功。
这个一般应用于两种场景:
我们来看下代码:
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 def do_something(): pass attemps = 0 success = Flase while attemps < 4 and not success: try: do_something() success = True except: attemps += 1 if attemps ==4: break
小屌丝:这个写法,不错呢。
小鱼:嗯,跟第一个相比,这个写法,更明确一下,也更高大上一些。
小屌丝:那还有更高大上的写法吗。
小鱼:那必须的,今天主角还没出场呢。
今天我们来说的这个模块,就是retrying,
也是第三方模块,主要是对程序中异常重试的一种优雅的解决方案。
安装方式,老规矩,直接pip安装:
pip install retrying
如果觉得每次都pip install 费时费力,那就看看小鱼这两篇:
《Python3,选择Python自动安装第三方库,从此跟pip说拜拜!!》
《Python3,我低调的只用一行代码,就导入Python所有库!》
retrying模块中,提供了一个装饰器函数retry;
装饰的函数会在运行失败的情况下重新执行,默认一直报错就一直重试,直到成功为止。
我们来看下代码
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 import random from retrying import retry #retry 装饰器 @retry def do_something_retry(): if random.randint(0,10) > 1: print(f'this is a test!') raise IOError('raise exception!') else: return "Nice!" print(do_something_retry())
小屌丝:为什么每次执行这段,都会打印出不同次数的"this is a test!"
小鱼:这是由于我们程序中只要随机整数大于1就会打印并且抛出异常。
但是由于我们有装饰器函数 retry,所以在发生异常就会重新再次执行方法,直到随机整数大于1,就会打印“Nice!”。
小屌丝:哦,这样啊,那我不想一直这么重试下去,能不能添加点限制之类的呢?
小鱼:嗯,可以的。我们不妨添加最大重试次数为4次。
代码展示
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 import random from retrying import retry #retry 装饰器添加最大次数限制 @retry(stop_max_attempt_number = 4) def do_something_times(): print(f"do something several times") raise Exception("raise exception") do_something_times()
小屌丝:真的呢,最多就是4次,那还有别的限制吗?
小鱼:这必须的。
代码展示
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 from retrying import retry # 限制最长重试时间(从执行方法开始计算) @retry(stop_max_delay = 4000) def do_something_intime(): print(f"do something in time") raise Exception("raise exception") do_something_intime()
代码展示
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 from retrying import retry # 设置固定重试时间 @retry(wait_fixed = 3000) def wait_fixed_time(): print(f"wait") raise Exception("raise exception") wait_fixed_time()
代码展示
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 from retrying import retry # 设置重试时间的随机范围 @retry(wait_random_min=1000,wait_random_max=2000) def wait_random_time(): print(f"wait") raise Exception("raise exception") wait_random_time()
代码展示
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 from retrying import retry #根据异常重试 def retry_if_io_error(exception): return isinstance(exception, IOError) # 设置特定异常类型重试 @retry(retry_on_exception=retry_if_io_error) def retry_special_error(): print(f"retry io error") raise IOError("raise exception") retry_special_error()
在这里,我们自己定义一个函数,判断异常类型,然后将函数作为参数传给装饰函数 retry ,如果异常类型符合,就会进行重试。
代码展示
# -*- coding: utf-8 -*- # @ auth : carl_DJ # @ time : 2021-11-19 from retrying import retry # 通过返回值判断是否重试 def retry_if_result_none(result): # return result is None if result =="123": return True @retry(retry_on_result=retry_if_result_none) def might_return_none(): print("Retry forever ignoring Exceptions with no wait if return value is None") return "123" might_return_none()
这里我们定义了一个判断返回值的函数,然后将这个函数作为参数传给 retry 装饰函数。当结果返回是“123”时,就会一直重试执行 might_return_none 函数。
在实际应用中,有的大佬偏向于使用第三方库,而有的大佬,喜欢自带的库。
不管是python自带的库,还是第三方库,在撸码过程中,能直接抛出异常,定位异常,就是最好。
所以,