
Python decorators are modules which can help create more code reusability and build efficiency of developers and designers. Python is a language known for its simplicity and elegance. Among its many powerful features, decorators stand out as a tool that enhances code modularity and reusability. If you have ever wanted to modify the behavior of a function without changing its core implementation, then decorators are the magic wand you need!
In this blog, we will go through thoroughly into Python decorators, understand their working, explore practical use cases, and learn how to create custom decorators. Additionally, we will examine real-world applications and the best practices for writing efficient decorators.
Decorators are widely used in Python frameworks, including Django and Flask, where they help in handling authentication, logging, and other pre/post-processing tasks.
| Higher-Order Functions |
|---|
| def shout(text): return text.upper() def whisper(text): return text.lower() def greet(func): return func(“Hello, World!”) print(greet(shout)) print(greet(whisper)) |
| Output:
HELLO, WORLD! hello, world! |
| A Simple Example of Python Decorators |
|---|
| #defining a simple decorator def my_decorator(func): def wrapper(): print(“Something is happening before the function is called.”) func() print(“Something is happening after the function is called.”) return wrapper #Using the decorator @my_decorator def say_hello(): print(“Hello, World!”) say_hello() |
| Output:
Something is happening before the function is called. Hello, World! Something is happening after the function is called. (Here my_decorator is wrapping the say_hello function and modifying its behavior without altering its actual code.) |
Decorators are something that makes code more reusable and readable. Some of the major reasons for using Python decorators include
| Function Decorators |
|---|
| import time def timer_decorator(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f”Execution time: {end_time - start_time: .4f} seconds”) return result return wrapper @timer_decorator def compute(): time.sleep(2) print(“Function execution complete!”) compute() |
| Class Decorators Example |
|---|
| class DecorateClass: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print(“Class decorator executed before the function call.”) return self.func(*args, **kwargs) @DecorateClass def greet(name): print(f”Hello, {name}!”) greet(“Alice”) |
| Built-In Decorators Example |
|---|
| class Person: def __init__(self, name, age): self.name = name self.age = age @property def info(self): return f”Name: {self.name}, Age: {self.age}” p = Person(“John”, 30) print(p.info) #accessing method as a property |
| Custom Decorators With Arguments Example |
|---|
| def repeat(n): def decorator(func): def wrapper(*args, **kwargs): for _ in range(n): func(*args, **kwargs) return wrapper return decorator @repeat(3) def greet(): print(“Hello”) greet() |
| Chaining Multiple Decorators Example |
|---|
| def uppercase(func): def wrapper(): return func().upper() return wrapper def exclaim(func): def wrapper(): return func() + "!!!" return wrapper @uppercase @exclaim def speak(): return "hello" print(speak()) # Output: HELLO!!! |
| Output: HELLO!!! |
To make the most out of Python decorators, here are some best practices to follow, mentioned below:
| Practice 1: Use of functools.wrap |
|---|
| import functools def my_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print("Decorator logic here") return func(*args, **kwargs) return wrapper @my_decorator def example(): """This is an example function.""" print("Function executed.") print(example.__name__) print(example.__doc__) |
| Output:
example This is an example function |
| Practice 3: Passing Arguments Dynamically |
|---|
| def flexible_decorator(func): def wrapper(*args, **kwargs): print("Arguments received:", args, kwargs) return func(*args, **kwargs) return wrapper @flexible_decorator def greet(name, message): print(f"{message}, {name}!") greet("Alice", message="Hello") |
| Practice 4: Chaining Decorators carefully |
|---|
| def uppercase(func): def wrapper(): return func().upper() return wrapper def exclaim(func): def wrapper(): return func() + "!!!" return wrapper @uppercase @exclaim def speak(): return "hello" print(speak()) |
| Output:
HELLO!!! |
| Practice 5: Document Decorators |
|---|
| def log_function_call(func): """Logs when a function is called.""" def wrapper(*args, **kwargs): print(f"Calling function {func.__name__}") return func(*args, **kwargs) return wrapper |