Search code examples
pythondecoratorpython-decorators

Can I pass an exception as an argument to a function in python?


I am new to python. I am trying to create a retry decorator that, when applied to a function, will keep retrying until some criteria is met (for simplicity, say retry 10 times).

def retry():
    def wrapper(func):
        for i in range(0,10):
            try:
                func()
                break
            except:
               continue
    return wrapper

Now that will retry on any exception. How can I change it such that it retries on specific exceptions. e.g, I want to use it like:

@retry(ValueError, AbcError)
def myfunc():
    //do something

I want myfunc to be retried only of it throws ValueError or AbcError.


Solution

  • You can supply a tuple of exceptions to the except .. block to catch:

    from functools import wraps
    
    def retry(*exceptions, **params):
        if not exceptions:
            exceptions = (Exception,)
        tries = params.get('tries', 10)
    
        def decorator(func):
            @wraps(func)
            def wrapper(*args, **kw):
                for i in range(tries):
                    try:
                        return func(*args, **kw)
                    except exceptions:
                        pass
            return wrapper
        return decorator
    

    The catch-all *exceptions parameter will always result in a tuple. I've added a tries keyword as well, so you can configure the number of retries too:

    @retry(ValueError, TypeError, tries=20)
    def foo():
        pass
    

    Demo:

    >>> @retry(NameError, tries=3)
    ... def foo():
    ...     print 'Futzing the foo!'
    ...     bar
    ... 
    >>> foo()
    Futzing the foo!
    Futzing the foo!
    Futzing the foo!