Python Decorator Introduction with Examples
1. Overview
The decorator pattern is a software design pattern that allows us to dynamically add functionality to classes without creating subclasses and affecting the behavior of other objects of the same class. By using the decorator pattern, we can easily generate different permutations of functionality that we might want without creating an exponentially increasing number of subclasses, making our code increasingly complex and bloated.
Decorators are usually implemented as sub-interfaces of the main interface that we want to implement and store an object of the main interface’s type. It will then modify the methods to which it wants to add certain functionality by overriding the methods in the original interface and calling on methods from the stored object.
2. Applications
Decorators are a good option to avoid expensive function rearrangements. A lot of Pythoners call this technique the “magic box” because you can come up with specific decorators that will bring you the desired output in an efficient manner. As will be shown below, I developed 3 different decorators that you could use in your Python code. Some of these decorators are:
Further development could be needed so feel free to copy and change it as fit.
2.1 Memoization
Memoization is a technique where the results of expensive function calls are cached to avoid redundant computations. However, this decorator is mostly recommended when the input value repeats often or the corresponding data has a lower cardinality. Otherwise, the memory will fill up and cause a stack overflow error.
领英推荐
def memoize(func):
cache = {}
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoize
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
Timing
A decorator to measure the execution time of a function. In my case, it helped me a lot to measure HBase and my database prototype query, insert, and deletion performance.
import time
def timing_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time} seconds.")
return result
return wrapper
@timing_decorator
def example_function():
# Some time-consuming operation
time.sleep(2)
Debugging
A decorator to print input arguments and the result of a function (I made it very simple just for the sake of the example).
def debug_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned: {result}")
return result
return wrapper
@debug_decorator
def add(a, b):
return a + b
References