Welcome, guest | Sign In | My Account | Store | Cart

Sometimes we want a function to be able to be retried automatically, such as a function that does networking trying to write/read data through a pre-established connection. Instead of writing try/except everywhere, a decorator would save much code and provide a single copy of code to do all the work.

Python, 35 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def conditional_retry(func=None, exceptions=Exception,
    action=None, callback_args=(), timeout=2):
    '''
    This decorator is able to be called with arguments.
    :keyword exceptions: exceptions in a tuple that will be
                         tested in the try/except
    :keyword action: a callable to be called at the end of every
                     time of re-attempt
    :keyword callback_args: arguments to be passed into the callable
    :keyword timeout: times of attempt, defaults to 2
    '''

    def decorated(func):
        def wrapper(*args, **kwargs):
            result = None
            i = 1
            while i <= timeout:
                try:
                    result = func(*args, **kwargs)
                    break
                except exceptions:
                    if i == timeout:
                        raise
                    if callable(action):
                        action(*callback_args)
                i += 1
            return result
        return wrapper

    if func is None: # in this case, the decorator is called with arguments
        def decorator(func):
            return decorated(func)
        return decorator
    # or the decorator is called without arguments
    return decorated(func)