Decorators in Python

In Python, decorators are a powerful and flexible feature that allows you to modify or extend the behavior of functions or methods without changing their actual code. Decorators are essentially higher-order functions that take a function as an argument and return a new function. They are denoted by the "@" symbol followed by the decorator name and placed above the function definition.

Creating a Basic Decorator

Let's define a simple decorator called my_decorator, which adds some additional functionality to a function.

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 @my_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.

In this example, we created a decorator my_decorator, which takes a function as an argument, wraps it with additional behavior (print statements in this case), and returns the modified function. We then applied the decorator to the say_hello function using the "@" syntax. When we call say_hello(), it actually calls the wrapper() function defined inside the my_decorator, effectively extending the behavior of the original say_hello function.

Decorators with Arguments

Decorators can also accept additional arguments if needed. To achieve this, we need to define a decorator factory, which is a function that returns a decorator.

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(name): print(f"Hello, {name}!") greet("Mary")
Output: Hello, Mary! Hello, Mary! Hello, Mary!

In this example, we created a decorator factory repeat, which takes an argument n and returns a decorator. The returned decorator, when applied to the greet function with @repeat(3), calls the greet function three times.


How to Create and Use Decorators in Python With simple Examples

Class-based Decorators

Decorators can also be implemented using classes. To create a class-based decorator, you need to define a class with a __call__() method, which will be called when the decorated function is called.

class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print("Something is happening before the function is called.") self.func(*args, **kwargs) print("Something is happening after the function is called.") @MyDecorator def say_hi(): print("Hi!") say_hi()
Output: Something is happening before the function is called. Hi! Something is happening after the function is called.

In this example, we created a class-based decorator MyDecorator, where the __init__() method is called when the decorator is applied, and the __call__() method is called when the decorated function is called.

Conclusion

Decorators are a powerful tool in Python, allowing you to add functionality, logging, validation, and more to functions and methods without modifying their original code. They promote clean and modular code by separating concerns and making the code more reusable and maintainable.