Python Decorators
$count++; if($count == 1) { include "../mobilemenu.php"; } ?> if ($count == 2) { include "../sharemediasubfolder.php"; } ?>
Decorators in Python are a powerful and versatile feature that allows you to modify the behavior of a function or class method. They are commonly used for logging, enforcing access control, instrumentation, caching, and more.
1. What is a Decorator?
A decorator is a function that takes another function (or method) as an argument and extends its behavior without explicitly modifying it. Decorators are often used in a syntactic sugar format using the `@decorator_name` syntax, making it easier to apply them to functions.2. Creating a Simple Decorator
Example: A simple decorator that logs the execution of a function.def simple_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
@simple_decorator
def say_hello():
print("Hello!")
say_hello()
Output:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
3. Decorators with Arguments
Sometimes, you may want to create decorators that accept arguments. To do this, you need an additional outer function.Example: A decorator that accepts a message.
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator_repeat
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
Output:
Hello, Alice!
Hello, Alice!
Hello, Alice!
4. Decorators for Class Methods
Decorators can also be used to modify methods in classes.Example: A decorator that logs method calls in a class.
def log_method_call(func):
def wrapper(self, *args, **kwargs):
print(f"Calling method: {func.__name__}")
return func(self, *args, **kwargs)
return wrapper
class MyClass:
@log_method_call
def say_hello(self):
print("Hello from MyClass!")
obj = MyClass()
obj.say_hello()
Output:
Calling method: say_hello
Hello from MyClass!
5. Using Built-in Decorators
Python comes with several built-in decorators, such as `@staticmethod`, `@classmethod`, and `@property`.a. @staticmethod
A static method does not receive an implicit first argument (like `self` or `cls`).
class Math:
@staticmethod
def add(x, y):
return x + y
print(Math.add(5, 3))
Output:
8
b. @classmethod
A class method receives the class as its implicit first argument.
class Math:
@classmethod
def multiply(cls, x, y):
return x * y
print(Math.multiply(4, 5))
Output:
20
c. @property
The property decorator allows you to define a method that can be accessed like an attribute.
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14 * (self.radius ** 2)
circle = Circle(5)
print(circle.area) # No parentheses needed
Output:
78.5
6. Chaining Decorators
You can apply multiple decorators to a single function by stacking them.Example: Using both logging and repetition decorators.
def log(func):
def wrapper(*args, **kwargs):
print(f"Function {func.__name__} is called")
return func(*args, **kwargs)
return wrapper
@repeat(2)
@log
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Bob")
Output:
Function say_hello is called
Hello, Bob!
Function say_hello is called
Hello, Bob!
7. The Functools Module
Python’s `functools` module provides utilities to work with decorators. The `@functools.wraps` decorator is commonly used to preserve the metadata of the original function.from functools import wraps
def log_with_wraps(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_with_wraps
def add(x, y):
return x + y
print(add(3, 4))
print(add.__name__) # Check the name of the function
Output:
Calling add
7
add
8. Real-World Use Cases of Decorators
1. Access Control: Restrict access to certain functions based on user permissions.2. Logging: Automatically log function calls and their arguments for debugging.
3. Caching: Cache results of expensive function calls to improve performance.
4. Timing Functions: Measure the time a function takes to execute.
Example: A simple timer decorator.
import time
def timer(func):
@wraps(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:.4f} seconds")
return result
return wrapper
@timer
def compute_square_sum(n):
return sum(i * i for i in range(n))
compute_square_sum(100000)
Output:
compute_square_sum took 0.0020 seconds
9. Conclusion
Decorators are a powerful feature in Python that enhance code reusability and readability. They allow you to modify the behavior of functions and methods dynamically. With the ability to create simple decorators, use built-in decorators, chain decorators, and apply advanced techniques with `functools`, decorators can greatly simplify complex tasks and provide clean solutions to various programming challenges.