当前位置: 首页 > 科技观察

Python异常可以写得这么优雅!

时间:2023-03-12 00:28:01 科技观察

本文转载自微信公众号《Python技术》,作者:佩森酱。转载本文请联系Python技术公众号。在写程序的时候,我们经常会遇到程序中的异常。这时,我们就不得不处理这些异常,以保证程序的健壮性。有以下版本用于处理异常。你通常做哪一种?对于不负责任的版本,什么都不做,让程序报错,会导致程序中断。对于简单的程序,这样做是没有问题的。大不了我遇到问题就解决,然后再运行。但是如果是复杂的系统,那就很麻烦了。也许你有一个异常阻塞了系统的运行,造成了灾难性的后果。简单处理版简单处理版是增加了异常捕获,出现异常时记录日志,通过日志定位异常。defdo_something():passdeflog_error(xxx):passtry:do_something()except:log_error(xxxx)改进处理版本改进简单处理版本,增加重试次数。这在爬虫程序中比较常见。第一次请求超时,过段时间可能会请求成功,所以重试几次可能会排除异常。attempts=0success=Falsewhileattempts<3andnotsuccess:try:do_something()success=Trueexcept:attempts+=1ifattempts==3:break但是这样还是不够优雅,很多地方可能要硬编码重试,看程序吧看起来很乱。今天给大家介绍一个第三方模块——retrying。它是程序中异常重试的优雅解决方案。安装使用安装命令还是那么不起眼:pipinstallretryinguse下面给大家介绍下这个装饰函数可以使用的参数。生命不息,奋斗不息。retrying提供了一个装饰器函数retry,被装饰的函数在失败时会重新执行,默认是一直报错就一直重试。importrandomfromretryingimportretry@retrydefdo_something_unreliable():ifrandom.randint(0,10)>1:print("justhaveatest")raiseIOError("raiseexception!")else:return"goodjob!"print(do_something_unreliable())运行这个程序,可以看到“justhaveatest”这句话每次打印的次数都不一样。这是因为在我们的程序中,只要随机整数大于1,就会打印并抛出异常。但是由于我们有装饰器函数retry,当出现异常时该方法会再次执行,直到随机整数大于1,“干得好!”将被打印。你不能太固执。这种无休止的重试是对生命和资源的浪费。我们要建设绿色家园,不妨加点限制:#maximumretrytimes@retry(stop_max_attempt_number=5)defdo_something_limited():print("dosomethingseveraltimes")raiseException("raiseexception")do_something_limited()珍惜有限的光阴一寸光阴一寸金,寸金难买寸光阴。我们要珍惜有限的时间,不妨给我们的重试加上一个时间限制:#限制最长重试时间(从执行方法计算)@retry(stop_max_delay=5000)defdo_something_in_time():print("dosomethingintime")raiseException("raiseexception")do_something_in_time()停下来欣赏路边的风景几十年的生活匆匆而过,不要一路狂奔而忘记欣赏路边的美景,有时候我们需要采取一些时间来欣赏沿途的美景:#设置固定的重试时间@retry(wait_fixed=2000)defwait_fixed_time():print("wait")raiseException("raiseexception")wait_fixed_time()设置失败的限制虽然我们需要屡败屡战的韧性,失败总要有个限度。在失败中度过一生:#设置重试时间的随机范围@retry(wait_random_min=1000,wait_random_max=2000)defwait_random_time():print("wait")raiseException("raiseexception")wait_random_time()有些人值得等待海中只想等对的人:#根据异常重试defretry_if_io_error(exception):returnisinstance(exception,IOError)#设置特定异常类型重试@retry(retry_on_exception=retry_if_io_error)defretry_special_error():print("retryioerror")raiseIOError("raiseexception")retry_special_error()我们定义一个判断异常类型的函数,然后将该函数作为参数传递给修饰函数retry。如果异常类型匹配,它将重试。有些结果是我们希望看到的生活并不是一帆风顺的。有时我们会遇到挫折。这些挫折可能是我们一开始想要的:#通过返回值判断是否重试defretry_if_result_none(result):"""ReturnTrueifweshouldretry(本例中resultisNone),Falseotherwise"""#returnresultisNoneifresult="111":returnTrue@retry(retry_on_result=retry_if_result_none)defmight_return_none():print("RetryforeverignoringExceptionswithnowaitifreturnvalueisNone")return"111"函数,然后将此函数作为参数传递给retry修饰函数。当结果为“111”时,它会一直重试执行might_return_none函数。生活是丰富多彩的,而不是单调的。我们的生活是丰富多彩的,从不单调。因此,我们可以将以上参数随意组合,并不局限于一次只能使用一个。比如遇到IOError可以限制重试,重试次数最多5次。