为函数的重试创建装饰器



我们有想要运行的函数example_2。有时它会引发一个例外,有时它不会。根据引发的异常,我想记录它(受控异常(或不记录它(非受控异常(。我还想重试函数example_2几次,前提是异常得到控制。

以下是我的尝试(基于《python中的干净代码》一书(:

from typing import Optional
from collections.abc import Sequence
import logging
from functools import wraps
class ControlledException(Exception):
"""My own customized exception"""
class UncontrolledException(Exception):
"""An exception I don't like/control """

logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)
logger = logging.getLogger('tcpserver')
_default_retries_limit = 3
def with_retry( retries_limit =_default_retries_limit, list_allowed_exceptions = None):
list_allowed_exceptions = list_allowed_exceptions or (ControlledException,)
def retry (operation):
@wraps(operation)
def wrapping_function(*args, **kwargs):
last_raised = None
for num in range(retries_limit):
print("Try number: {}".format(num+1))
try:
return operation(*args, **kwargs)
except list_allowed_exceptions as raised_exception:
logger.warning("returning %s due to %s",operation.__qualname__,raised_exception)
logger.warning('Protocol problem: %s', 'connection reset', extra=d)
last_raised = raised_exception
raise last_raised
return wrapping_function
return retry
@with_retry(retries_limit = 5, list_allowed_exceptions = ControlledException)
def run_operation(task):
print("Task result: {}".format(task))
def example_2(threshould_1,threshould_2):
"""random.random() draws from a uniform distribution"""
print('Called example function')
value = random()
if value < threshould_1:
print("value = ", value)
raise ControlledException
elif value > threshould_1 and value < threshould_2:
print("value = ", value)
raise UncontrolledException
return value

当我调用run_operation(example_2(0.9,0.0)),并且当ControlledException被引发时,try命令的except分支中什么都不运行。。。为什么?

编辑:

如果我做

@with_retry(...) 
run_operation(...)

那么我就不去例外。但如果我做

@with_retry(...)
example_2(...)

然后我去例外。现在我不明白为什么这会有所不同?

根据注释:

运行:

run_operation(example_2(0.9,0.0))

相当于:

my_result = example_2(0.9,0.0)
run_operation(my_result)

如果CCD_ 3是"0";"受保护";,但是example_2可以抛出异常(或者…确实抛出异常(;"保护";由装饰师提供的将永远不会发生。。。因为run_operation永远不会到达。

当Python看到this:run_operation(example_2(0.9,0.0))时,它将首先(完全地(调用example_2(0.9,0.0),然后它将(尝试(获取结果,并使用调用example_2返回的任何值来调用run_operation

在这种情况下,在尝试调用run_operation之前,调用example_2(0.9,0.0)已经抛出了一个Exception。

最新更新