Decorator in Python
A decorator is one of the python’s useful syntaxes that literally decorate functions, methods and even classes.
A Typical Example of Python Decorator
Many blog posts demonstrate decorators using logging or print statements, as shown in the following example:
import time
# make decorator
def exec_time(func):
def wrapper(*args, **kwargs):
starttime = time.perf_counter()
res = func(*args, **kwargs)
func_exec_time = time.perf_counter() - starttime
print(f"function - `{func.__name__}` conducted in {func_exec_time}s")
return res
return wrapper
# decorate function with `@exec_time`
@exec_time
def add(a:int, b:int):
return a + b
# usage
add(100, 30)
The expected output will be as follows:
function - `add` conducted in 6.659999999998611e-07s
A Practical Example of Python Decorator
However, my favorite use case for Python decorators is implementing the Singleton pattern with existing functions, methods, or classes as follows:
import threading
# make singleton decorator
def singleton(func):
lock = threading.Lock() # If you need thread-safe one
def wrapper(*args, **kwargs):
with lock:
if wrapper.instance is None:
wrapper.instance = func(*args, **kwargs)
return wrapper.instance
wrapper.instance = None # Ensuring attribute always exists before execution
return wrapper
# decorate class with `@singleton`
@singleton
class MySingleton:
def __init__(self, value):
self.value = value
def get_value(self):
return self.value
# usage
instance1 = MySingleton(100)
instance2 = MySingleton(30)
print("is instance 1 is the same with instance 2?")
print(instance1 is instance2)
print("is instance 1 value")
print(instance1.get_value())
print("is instance 2 value")
print(instance2.get_value())
Then the expected output will be as follows:
is instance 1 is the same with instance 2?
True
is instance 1 value
100
is instance 2 value
100
Conclusion
Python decorator is powerful because it helps to modify the functionilty of codes without less modifications.