简体   繁体   English

如何在装饰器中捕获异常

[英]How to catch an exception in a decorator

I have a function my cause exception and i want it to be a decorator. 我有一个函数,我的原因异常,我希望它成为装饰器。 The code is as follow: 代码如下:

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'

but the output is: 但输出是:

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

so, how can I catch this exception? 因此,如何捕获此异常?

The exception is raised when you define the function. 定义函数时会引发异常。 The only way to catch this exception would be: 捕获此异常的唯一方法是:

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

If it's confusing why this is causing an exception, remember your code is equivalent to: 如果这引起异常的原因令人困惑,请记住您的代码等效于:

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

So, right now your code basically boils down to this: 因此,现在您的代码基本上可以归结为:

_des = des(1)

def _func();
    print '!!'

func = _des(func)

You're using the return value of des as the decorator, and I think that is causing the problem. 您使用des的返回值作为装饰器,我认为这是造成问题的原因。

I think you might want to nest that returned function one more time: 我想您可能想再嵌套一次返回的函数:

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

I am missing one function level here. 我在这里缺少一个功能级别。

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'

As the other answers have explained, your current issue is that you're getting the exception raised when the decorator is applied to the function, not when the function is called. 正如其他答案所解释的那样,当前的问题是,在将装饰器应用于函数时(而不是在调用函数时)引发了异常。

To fix this, you need to make the decorator return a function that does the exception raising. 要解决此问题,您需要使装饰器返回一个进行异常引发的函数。 Here's how that could work: 这是可能的工作方式:

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

The des function is a "decorator factory". des功能是一个“装饰工厂”。 It doesn't really doesn't do anything other than providing a scope to hold the i parameter for the decorator that it returns. 除了提供一个范围来保存返回的装饰器的i参数外,它实际上并没有做任何其他事情。

The decorator function does the check to see if anything special needs to be done. decorator功能进行检查,看是否需要做一些特殊的事情。 If not, it returns the decorated function unmodified. 如果不是,则返回修饰后的函数,不做修改。 If i==1 , it returns a custom function. 如果i==1 ,则返回自定义函数。

The raiser function is the decorator's return value if i==1 . 如果i==1raiser函数是装饰器的返回值。 It always raises an exception when it is called. 总是在调用时引发异常。 The functools.wraps decorator applied to it is not strictly necessary, but it makes it look more like the original function (same __name__ , __doc__ , etc). functools.wraps适用于它的装饰是不是绝对必要的,但它使得它看起来更像原来的功能(同__name____doc__等)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM