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.
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)