4

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

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

4 回答 4

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)
于 2013-08-20T04:55:04.427 回答
2

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

_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 "!!"
于 2013-08-20T04:57:10.373 回答
2

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

要解决此问题,您需要使装饰器返回一个引发异常的函数。这是如何工作的:

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,它返回一个自定义函数。

raiser函数是装饰器的返回值 if i==1。它总是在被调用时引发异常。应用于它的functools.wraps装饰器不是绝对必要的,但它使它看起来更像原始函数(相同__name__,,__doc__等)。

于 2013-08-20T06:07:29.267 回答
1

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

ITEM

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'
于 2013-08-20T05:29:26.650 回答