Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 995
LiGa Avatar asked Mar 22 '23 17:03

LiGa


1 Answers

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". It doesn't really doesn't do anything other than providing a scope to hold the i parameter for the decorator that it returns.

The decorator function does the check to see if anything special needs to be done. If not, it returns the decorated function unmodified. If i==1, it returns a custom function.

The raiser function is the decorator's return value if i==1. 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).

like image 175
Blckknght Avatar answered Apr 06 '23 20:04

Blckknght