如何在装饰器中捕获异常

时间:2013-08-20 04:34:44

标签: python python-decorators

我有一个函数我的原因异常,我希望它是一个装饰器。代码如下:

def des(i):
    def new_func(func):
        if i == 1:
            raise Exception
        else:
            return func
    return new_func


@des(1)
def func():
    print "!!"


if __name__ == '__main__':
    try:
        func()
    except Exception:
        print 'error'

但输出是:

Traceback (most recent call last):
  File "D:/des.py", line 10, in <module>
    @des(1)
  File "D:/des.py", line 4, in new_func
    raise Exception
Exception

所以,我怎么能抓住这个例外?

4 个答案:

答案 0 :(得分:2)

定义函数时会引发异常。捕获此异常的唯一方法是:

try:
    @des(1)
    def func():
        print '!!'
except:
    print 'error'

如果引起异常的原因令人困惑,请记住您的代码等同于:

def func():
    print '!!'
func = des(1)(func)
# des(1) = new_func, so des(1)(func) is new_func(func)

答案 1 :(得分:1)

所以,现在你的代码基本归结为:

_des = des(1)

def _func();
    print '!!'

func = _des(func)

您使用des的返回值作为装饰器,我认为这会导致问题。

我想你可能想再次嵌套返回的函数:

def des(i): # container func.
    def new_func(func):
        def ret_func(*args, **kwargs):
            if i == 1:
                raise Exception
            else:
                return func(*args, **kwargs)

        return ret_func # return the func with the bound variable
    return new_func # return the func which creates the function w/ the bound var.


@des(1)
def func():
    print "!!"

答案 2 :(得分:0)

我在这里缺少一个功能级别。

ITYM

import functools
def des(i): # this is the "decorator creator", called with des(1)
    def deco(func): # this is returned and is the real decorator, called at function definition time
        @functools.wraps(func) # sugar
        def new_func(*a, **k): # and this is the function called on execution.
            if i == 1:
                raise Exception # I hope this is just for testing... better create a new exception for this
            else:
                return func(*a, **k)
        return new_func
    return deco

@des(1)
def func():
    print "!!"

if __name__ == '__main__':
    try:
        func()
    except Exception:
        print 'error'

答案 3 :(得分:0)

正如其他答案所解释的那样,您当前的问题是,当装饰器应用于函数时,您将获得异常,而不是在调用函数时。

要解决此问题,您需要让装饰器返回一个执行异常提升的函数。这是如何工作的:

import functools

def des(i):
    def decorator(func):
        if i != 1:
            return func # no wrapper needed

        @functools.wraps(func)
        def raiser(*args, **kwargs):
            raise Exception

        return raiser

    return decorator

des函数是“装饰工厂”。除了提供一个范围来保存它返回的装饰器的i参数之外,它实际上没有做任何事情。

decorator函数会检查是否需要执行任何特殊操作。如果不是,则返回未修改的修饰函数。如果i==1,则返回自定义函数。

如果raiseri==1函数是装饰者的返回值。它在调用时总是引发异常。应用functools.wraps装饰器并非绝对必要,但它使其看起来更像原始函数(相同__name____doc__等)。