Browse Source

Adding example of decorator

Swaroop C H 12 years ago
parent
commit
47035101b6
1 changed files with 72 additions and 0 deletions
  1. 72 0
      17-more.md

+ 72 - 0
17-more.md

@@ -221,6 +221,78 @@ The `assert` statement should be used judiciously. Most of the time,
 it is better to catch exceptions, either handle the problem or display
 it is better to catch exceptions, either handle the problem or display
 an error message to the user and then quit.
 an error message to the user and then quit.
 
 
+## Decorators ##
+
+Decorators are a shortcut to applying wrapper functions. This is
+helpful to "wrap" functionality with the same code over and over
+again. For example, I created a `retry` decorator for myself that I
+can just apply to any function and if any exception is thrown during a
+run, it is retried again, till a maximum of 5 times and with a delay
+between each retry. This is especially useful for situations where you
+are trying to make a network call to a remote computer:
+
+~~~python
+from time import sleep
+from functools import wraps
+import logging
+logging.basicConfig()
+log = logging.getLogger("retry")
+
+
+def retry(f):
+    @wraps(f)
+    def wrapped_f(*args, **kwargs):
+        MAX_ATTEMPTS = 5
+        for attempt in range(1, MAX_ATTEMPTS + 1):
+            try:
+                return f(*args, **kwargs)
+            except:
+                log.exception("Attempt %s/%s failed : %s",
+                              attempt,
+                              MAX_ATTEMPTS,
+                              (args, kwargs))
+                sleep(10 * attempt)
+        log.critical("All %s attempts failed : %s",
+                     MAX_ATTEMPTS,
+                     (args, kwargs))
+    return wrapped_f
+
+
+counter = 0
+
+
+@retry
+def save_to_database(arg):
+    print("Write to a database or make a network call or etc.")
+    print("This will be automatically retried if exception is thrown.")
+    global counter
+    counter += 1
+    if counter < 2:
+        raise ValueError(arg)
+
+
+if __name__ == '__main__':
+    save_to_database("Some bad value")
+~~~
+
+Output:
+
+~~~
+$ python3 retry_decorator.py
+
+Write to a database or make a network call or etc.
+This will be automatically retried if exception is thrown.
+ERROR:retry:Attempt 1/5 failed : (('Some bad value',), {})
+Traceback (most recent call last):
+  File "/tmp/retry_decorator.py", line 14, in wrapped_f
+    return f(*args, **kwargs)
+  File "/tmp/retry_decorator.py", line 37, in save_to_database
+    raise ValueError(arg)
+ValueError: Some bad value
+Write to a database or make a network call or etc.
+This will be automatically retried if exception is thrown.
+~~~
+
 ## Differences between Python 2 and Python 3 ##
 ## Differences between Python 2 and Python 3 ##
 
 
 Read these articles:
 Read these articles: