为函数的重试创建装饰器

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) 已经抛出异常。