Decorating functions with classes
A decorator does not have to be a function. In Python, it could be a class that plays the role of a decorator as a function.
We can define a decorator as a class, and in order to do that, we have to use a __call__
special class method. When a user needs to create an object that acts as a function (i.e., it is callable) then the function decorator needs to return an object that is callable, so the __call__
special method will be very useful.
Our previous example code:
def simple_decorator(own_function):
def internal_wrapper(*args, **kwargs):
print('"{}" was called with the following arguments'.format(own_function.__name__))
print('\t{}\n\t{}\n'.format(args, kwargs))
own_function(*args, **kwargs)
print('Decorator is still operating')
return internal_wrapper
could be transcribed to the code presented on the right. Run it to see the output and compare it to the output of the previously retrieved output.
A short explanation of special methods:
- the
__init__
method assigns a decorated function reference to the self.attribute for later use; - the
__call__
method, which is responsible for supporting a case when an object is called, calls a previously referenced function.
The advantage of this approach, when compared to decorators expressed with functions, is:
- classes bring all the subsidiarity they can offer, like inheritance and the ability to create dedicated supportive methods.
Code
class SimpleDecorator:def __init__(self, own_function):
self.func = own_function
def __call__(self, *args, **kwargs):
print('"{}" was called with the following arguments'.format(self.func.__name__))
print('\t{}\n\t{}\n'.format(args, kwargs))
self.func(*args, **kwargs)
print('Decorator is still operating')
@SimpleDecorator
def combiner(*args, **kwargs):
print("\tHello from the decorated function; received arguments:", args, kwargs)
combiner('a', 'b', exec='yes')
{{ dockerServerErrorMsg }}
×
{{ errorMsg }}
×
{{ successMsg }}
×