Class as Decorator in Python
Last Updated :
29 Jul, 2024
While function-based decorators are widely used, class-based decorators can offer more flexibility and better organization, especially when the decorator needs to maintain state or requires multiple methods to function properly. A Python class decorator is simply a class that implements the __call__
method, allowing an instance of the class to be used as a decorator.
This article explores the concept of using classes as decorators in Python, illustrating their purpose, implementation, and benefits through practical examples.
Implementing Class Decorators
Example: Let's consider a simple example where we use a class decorator to log the execution time of a function:
Python
import time
class TimerDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
start_time = time.time()
result = self.func(*args, **kwargs)
end_time = time.time()
print(f"Function {self.func.__name__} executed in {end_time - start_time} seconds")
return result
@TimerDecorator
def example_function(n):
total = 0
for i in range(n):
total += i
return total
# Usage
print(example_function(1000000))
OutputFunction example_function executed in 0.06820821762084961 seconds
499999500000
Class Decorator with *args and **kwargs
In this example, the class decorator demonstrates how you can modify the return value of a function, adding additional logic to its execution.
Example:
- LoggerDecorator Class:
- The
__init__
method takes the function to be decorated and stores it. - The
__call__
method logs the arguments and keyword arguments, calls the original function with these arguments, and returns the result.
- greet Function:
- This is a simple function that takes a name and an optional greeting message.
- Using the Decorator:
- When
greet
is called, the LoggerDecorator
logs the arguments before executing the function.
Python
class LoggerDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(f"Arguments: {args}, Keyword Arguments: {kwargs}")
result = self.func(*args, **kwargs)
return result
@LoggerDecorator
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
# Usage
print(greet("Alice"))
print(greet("Bob", greeting="Hi"))
OutputArguments: ('Alice',), Keyword Arguments: {}
Hello, Alice!
Arguments: ('Bob',), Keyword Arguments: {'greeting': 'Hi'}
Hi, Bob!
Class Decorator with return Statement
In this example, the class decorator demonstrates how you can modify the return value of a function, adding additional logic to its execution.
Example:
- DoubleReturnDecorator Class:
- The
__init__
method takes the function to be decorated and stores it. - The
__call__
method calls the original function with the provided arguments, then doubles the result and returns it.
- add Function:
- This is a simple function that adds two numbers.
- Using the Decorator:
- When
add
is called, the DoubleReturnDecorator
modifies the return value by doubling it before returning it.
Python
class DoubleReturnDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
result = self.func(*args, **kwargs)
return result * 2
@DoubleReturnDecorator
def add(a, b):
return a + b
# Usage
print(add(3, 5))
print(add(10, 20))
Checking for an Invalid Parameter with a Class Decorator
In this example, the class decorator demonstrates how you can check for specific parameter values and handle errors appropriately by raising exceptions when conditions are not met.
Example
- ErrorCheckDecorator Class:
- The
__init__
method takes the function to be decorated and stores it. - The
__call__
method checks if the error
keyword argument is set to True
. If it is, it raises a ValueError
. Otherwise, it calls the original function with the provided arguments.
- process_data Function:
- This is a simple function that takes some data and an optional
error
flag.
- Using the Decorator:
- When
process_data
is called with error=True
, the decorator raises a ValueError
. Otherwise, it processes the data normally.
Python
class ErrorCheckDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
if kwargs.get('error', False):
raise ValueError("Invalid parameter 'error' set to True")
return self.func(*args, **kwargs)
@ErrorCheckDecorator
def process_data(data, error=False):
return f"Processing data: {data}"
# Usage
try:
print(process_data("sample_data"))
print(process_data("sample_data", error=True)) # This will raise ValueError
except ValueError as e:
print(e)
OutputProcessing data: sample_data
Invalid parameter 'error' set to True
Similar Reads
Python Class Members Python, similarly to other object-oriented allows the user to write short and beautiful code by enabling the developer to define classes to create objects. The developer can define the prototype of an object class based on two types of members: Instance membersClass members In the real world, these
6 min read
Built-In Class Attributes In Python Python offers many tools and features to simplify software development. Built-in class attributes are the key features that enable developers to provide important information about classes and their models. These objects act as hidden gems in the Python language, providing insight into the structure
4 min read
Private Attributes in a Python Class In Python, encapsulation is a key principle of object-oriented programming (OOP), allowing you to restrict access to certain attributes or methods within a class. Private attributes are one way to implement encapsulation by making variables accessible only within the class itself. In this article, w
2 min read
Python Program to Get the Class Name of an Instance In this article, we will see How To Get a Class Name of a class instance. For getting the class name of an instance, we have the following 4 methods that are listed below: Using the combination of the __class__ and __name__ to get the type or class of the Object/Instance.Use the type() function and
4 min read
How To Make a Subclass from a Super Class In Python In Python, you can create a subclass from a superclass using the class keyword, and by specifying the superclass in parentheses after the subclass name. The subclass inherits attributes and behaviors from the superclass, allowing you to extend or modify its functionality while reusing the existing c
3 min read