Python Class Decorators

Summary: in this tutorial, you’ll learn about Python class decorators. After the tutorial, you’ll know how to define classes as decorators.

Introduction to the Python class decorators

So far you have learned how to use functions to define decorators.

For example, the following star function prints out a number of * characters before and after calling the decorated function:

def star(n):
    def decorate(fn):
        def wrapper(*args, **kwargs):
            print(n*'*')
            result = fn(*args, **kwargs)
            print(result)
            print(n*'*')
            return result
        return wrapper
    return decorateCode language: Python (python)

The star is a decorator factory that returns a decorator. It accepts an argument that specifies the number of * characters to display.

The following illustrates how to use the star decorator factory:

@star(5)
def add(a, b):
    return a + b


add(10, 20)Code language: Python (python)

Output:

*****
30
*****

The star() decorator factory takes an argument and returns a callable. The callable takes an argument (fn) which is a function that will be decorated. Also, the callable can access the argument (n) passed to the decorator factory.

A class instance can be a callable when it implements the __call__ method. Therefore, you can make the __call__ method as a decorator.

The following example rewrites the star decorator factory using a class instead:

class Star:
    def __init__(self, n):
        self.n = n

    def __call__(self, fn):
        def wrapper(*args, **kwargs):
            print(self.n*'*')
            result = fn(*args, **kwargs)
            print(result)
            print(self.n*'*')
            return result
        return wrapperCode language: Python (python)

And you can use the Star class as a decorator like this:

@Star(5)
def add(a, b):
    return a + bCode language: Python (python)

The @Star(5) returns an instance of the Star class. That instance is a callable, so you can do something like:

add = Star(5)(add)Code language: Python (python)

So you can use callable classes to decorate functions.

Put it all together:

from functools import wraps


class Star:
    def __init__(self, n):
        self.n = n

    def __call__(self, fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            print(self.n*'*')
            result = fn(*args, **kwargs)
            print(result)
            print(self.n*'*')
            return result
        return wrapper


@Star(5)
def add(a, b):
    return a + b


add(10, 20)Code language: Python (python)

Summary

  • Use callable classes as decorators by implementing the __call__ method.
  • Pass the decorator arguments to the __init__ method.
Did you find this tutorial helpful ?