使用Python decorator处理try和exception

使用Python decorator处理try和exception,python,decorator,Python,Decorator,如何以decorator方式传递try函数和异常处理函数 例如,这是WCF连接 def wcf(): def send_request(result): # establish connection... result["response"] = True def handle_execption(e, result): # logger something result["error"] = str(e)

如何以decorator方式传递try函数和异常处理函数

例如,这是
WCF
连接

def wcf():
    def send_request(result):
        # establish connection...
        result["response"] = True

    def handle_execption(e, result):
        # logger something
        result["error"] = str(e)
    result = {}
    try:
        send_request(result)
    except Exception as e:
        handle_execption(e, result)
现在,我想为这个连接添加一个重试机制。 实现这一点的最佳方式是什么,我有多种连接方式(如
REST
SOAP
WCF
,等等)?通常,它们共享相同的模式,并且都具有
send\u request
handle\u execption

硬代码类似于以下内容,但在每个协议中添加相同的逻辑是相当愚蠢的

for attempt in range(0, 3):
    sleep_seconds = attempt ** 2
    sleep(sleep_seconds)

    try:
        send_request(result)
        break
    except Exception as e:
        handle_execption(e, result)

为什么是装修工?我觉得它和我的一样干净

def wcf():
def发送请求(结果):
#建立连接。。。
结果[“响应”]=真
def句柄_异常(e,结果):
#什么
结果[“错误”]=str(e)
返回重试(发送请求,处理异常)
def重试(发送请求,处理异常):
结果={}
对于在范围(0,3)内的尝试:
睡眠(尝试**2)
尝试:
发送请求(结果)
返回结果
例外情况除外,如e:
返回句柄\执行选项(e,结果)

如果您总是以相同的方式处理异常,则可以编写一个装饰程序,对该行为进行硬编码并处理重试逻辑:

def retry_decorator(base_function):
    def new_function(*args, **kwargs):  # This allows you to decorate functions without worrying about what arguments they take
        for attempt in range(3):
            sleep_seconds = attempt ** 2
            sleep(sleep_seconds)

            try:
                return base_function(*args, **kwargs)  # base_function is whatever function this decorator is applied to
            except Exception as e:
                print(e)  # Replace this with whatever you want, as long as it's the same for all possible base_functions

    return new_function


@retry_decorator  # Replaces send_request() with retry_decorator(send_request)()
def send_request(result):
    result["response"] = True
如果要对不同的连接使用不同的异常处理逻辑,事情会变得更复杂:

def retry_decorator_2(exception_handle_function):
    def new_decorator(base_function):
        def new_function(*args, **kwargs):
            for attempt in range(3):
                sleep_seconds = attempt ** 2
                sleep(sleep_seconds)

                try:
                    return base_function(*args, **kwargs)
                except Exception as e:
                    exception_handle_function(e)

        return new_function

    return new_decorator


@retry_decorator_2(print)  # Replace 'print' with an exception handling function
def send_request(result):
    result["response"] = True
在这种情况下,
retry\u decorator\u 2(print)
创建一个新的decorator(将
print
存储为
exception\u handle\u函数
),然后将该decorator应用于
发送请求
函数

如果需要
exception\u handle\u函数
获取参数,可以将它们作为装饰器的一部分传递:

def retry_decorator_3(exception_handle_function, *exception_function_args, **exception_function_kwargs):
    def new_decorator(base_function):
        def new_function(*args, **kwargs):
            for attempt in range(3):
                sleep_seconds = attempt
                sleep(sleep_seconds)

                try:
                    return base_function(*args, **kwargs)
                except Exception as e:
                    exception_handle_function(e, *exception_function_args, **exception_function_kwargs)

        return new_function

    return new_decorator


@retry_decorator_3(print, 1, 2, 3)  # 1, 2, 3 become arguments for the print function, or whatever you replace it with
def send_request(result):
    result["response"] = True

您不必增加for循环中的尝试次数,也不必使用if语句睡眠哦,您是对的,谢谢@Alexandergolys不应该
result
成为
dict
而不是列表,即
result={}
而不是
result=[]
?@md2perpe,确切地说。。。。谢谢,这是一个很好的观点。如果我们很固执,为了学习透视图,你知道如何把他们改写成装饰师吗?这太棒了,还有一个问题。如果我们想将参数传递到
异常处理\函数
,该怎么办@水鬼