装饰器函数中的异常处理

Wil*_*ill 1 python exception decorator python-2.7

我是 Python 新手,有很多函数可以在某些硬件上执行各种任务。每个函数都有不同数量的参数和返回值。

我想制作一种通用的“重试”包装函数,它将捕获我的任何函数的异常并执行一些错误处理(例如重试任务)。

据我了解,我应该能够使用装饰器函数作为每个函数的通用包装器。这似乎有效,但我似乎无法真正从装饰器函数中调用的函数中获得任何异常。

我查看了各种示例并得出了以下结论:

def retry(function):
    def _retry(*args, **kwargs):
        try:
            reply = function(*args, **kwargs)
            print "reply: ", reply
            return reply
        except PDError as msg:
            print "_retry", msg
        except:
            print "_retry: another error"
    return _retry
Run Code Online (Sandbox Code Playgroud)

然后我使用我的函数之一的名称来调用它:

value = retry(pd.command_get_parameter(0x00))
Run Code Online (Sandbox Code Playgroud)

它似乎调用了我的函数并正确返回,但我的重试函数中从未捕获异常。所以我无法处理错误并重试。

我也尝试过这个:

from functools import wraps

def retry(function):
    @wraps(function)
    def _retry(*args, **kwargs):
    .....
Run Code Online (Sandbox Code Playgroud)

我不确定我做错了什么,或者这是否是最好的方法。有人对如何做到这一点有建议吗?我真的不想为每个主要功能创建单独的“重试”功能。

Ult*_*nct 7

将我的评论转换为答案:

你应该使用像:

def retry(function):
    @wraps(function)
    def _retry(*args, **kwargs):
        try:
            reply = function(*args, **kwargs)
            print "reply: ", reply
            return reply
        except PDError as msg:
            print "_retry", msg
        except:
            print "_retry: another error"
    return _retry

class SomeClass(object):

    @retry
    def command_get_parameter(..):
        return <some value>
s = SomeClass()
result = s.command_get_parameter(..)  #retry(..) actually invokes this function. 
Run Code Online (Sandbox Code Playgroud)

装饰器接受一个函数,并返回一个装饰函数。装饰是能够在调用函数之前、之后执行某些操作或捕获异常等的东西。如果您使用上述语法 ( ,则@retry)解释器调用retry(..),传入函数对象 ( command_get_parameter),并将该函数替换为由retry(command_get_parameter).返回的函数

发生的事情有点类似于以下步骤(伪代码):

new_command_get_parameter = retry(command_get_parameter) #@retry has this effect.
result = new_command_get_parameter(your_input)
Run Code Online (Sandbox Code Playgroud)

不同之处在于,上述两个步骤是由解释器神奇地为您完成的——保持代码更清晰、更易读。


当前您正在调用该函数,并将其结果传递给它,retry(..)这显然是错误的。此外,它不会按照您想要的方式捕获异常。


更新:如果您希望重试访问实例变量,您所要做的就是让_retry使用第一个参数为self。就像是:

def retry(func):
    def _retry(self, *args, **kwargs):
        print "Decorator printing a:", self.a
        print "Decorator printing b:", self.b
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print "Caught exception"
            return "Grr.."
    return _retry


class Temp(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    @retry
    def command(self, *args, **kwargs):
        print "In command."
        print "Args:", args
        print "KWargs:", kwargs

        raise Exception("DIE!")

t = Temp(3, 5)

print t.command(3,4,5, a=4, b=8)
Run Code Online (Sandbox Code Playgroud)

输出

Decorator printing a: 3
Decorator printing b: 5
In command.
Args: (4, 5)
KWargs: {'a': 4, 'b': 8}
Caught exception
Grr..
Run Code Online (Sandbox Code Playgroud)