Module (45%)
Section (62%)

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 }} ×