为函数的重试创建装饰器
Creating a decorator for retries of a function
我们有函数 example_2,我们想要 运行。有时它会引发异常,有时不会。
根据引发的异常,我想记录它(受控异常)或不记录(不受控异常)。我还想重试函数 example_2 几次,前提是异常得到控制。
这是我的尝试(基于书'clean code in 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)
如果 run_operation
是“受保护的”,但是 example_2
可以抛出异常(或者... 确实 抛出异常),则装饰器提供的“保护”永远不会发生...因为永远不会达到run_operation
。
当 Python 看到 这个: run_operation(example_2(0.9,0.0))
它会首先调用 example_2(0.9,0.0)
(完全和完全)然后 theeeEEEeen 它会(尝试)获取结果并使用调用 example_2.
返回的任何值调用 run_operation
在这种情况下,在尝试调用 run_operation
之前,调用 example_2(0.9,0.0)
已经抛出异常。
我们有函数 example_2,我们想要 运行。有时它会引发异常,有时不会。 根据引发的异常,我想记录它(受控异常)或不记录(不受控异常)。我还想重试函数 example_2 几次,前提是异常得到控制。
这是我的尝试(基于书'clean code in 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)
如果 run_operation
是“受保护的”,但是 example_2
可以抛出异常(或者... 确实 抛出异常),则装饰器提供的“保护”永远不会发生...因为永远不会达到run_operation
。
当 Python 看到 这个: run_operation(example_2(0.9,0.0))
它会首先调用 example_2(0.9,0.0)
(完全和完全)然后 theeeEEEeen 它会(尝试)获取结果并使用调用 example_2.
run_operation
在这种情况下,在尝试调用 run_operation
之前,调用 example_2(0.9,0.0)
已经抛出异常。