Python 如何捕获装饰器中的异常

Python 如何捕获装饰器中的异常,python,python-decorators,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:

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

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
回溯(最近一次呼叫最后一次):
文件“D:/des.py”,第10行,在
@des(1)
文件“D:/des.py”,第4行,在新函数中
引发异常
例外情况

那么,如何捕获此异常呢?

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

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)

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

_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 "!!"

我这里缺少一个功能级别

伊蒂姆


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

要解决这个问题,您需要使decorator返回一个执行异常引发的函数。以下是如何做到这一点:

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


如果
i==1
,则
raiser
函数是装饰器的返回值。它在被调用时总是引发异常。应用于它的
functools.wrapps
装饰器并非绝对必要,但它使它看起来更像原始函数(相同的
\uuuuuuu name\uuuuuuu
\uuuu doc\uuuuuuu
,等等)。

我相信这可能与您的问题有关:它工作,我理解它是如何工作的。谢谢:)但这会导致func出现未定义的函数是的,如果在定义函数的过程中出现异常,则不会定义该函数。除了在
except
语句中为
func
分配一个不同的函数之外,真的没有办法解决这个问题。如果我知道实际的代码是什么,而不是这个示例,我可以提供更多帮助。@LiGa是的,但您可以通过异常检测到这一点并进行适当的处理。我想您希望最内部的函数调用
func
,而不仅仅是返回它。也就是说,将
return func
替换为
return func()
。您可能希望使用varargs语法(
*args,**kwargs
)来允许修饰函数也接受一些参数。@Blckknght但是缺少一个级别的函数。看看我的答案。@glglgl:我不确定我是否明白。cwallenpool的答案有正确数量的嵌套函数,尽管没有您的答案那么简洁(并且没有
()
使最里面的函数工作)。实际上,您可以在
i==1
上设置创建最内层函数的条件,如果不需要,只需从装饰器(第二级函数)返回
func
。@Blckknght是的,但是函数的装饰失败,而不是调用。@Blckknght d'oh!好了,现在修好了。这也是一个很好的解决方案:
i==1
之间的区别=
尽可能早地发生,但异常会在调用时发生,这是首选的。
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