Python Decorator with Arguments

Summary: in this tutorial, you’ll learn how to define Python decorators with arguments by using a decorator factory.

Introduction to Python decorator with arguments

Suppose that you have a function called say that simply prints out a message:

def say(message): ''' print the message Arguments message: the message to show ''' print(message)
Code language: Python (python)

Suppose that you want to execute the say function 5 times repeatedly each time you call it. For example:

say('Hi')
Code language: Python (python)

It should show the following the Hi message five times as follows:

Hi Hi Hi Hi Hi

To do that, you can use a regular decorator:

@repeat def say(message): ''' print the message Arguments message: the message to show ''' print(message)
Code language: Python (python)

And you can define the repeat decorator as follows:

def repeat(fn): @wraps(fn) def wrapper(*args, **kwargs): for _ in range(5): result = fn(*args, **kwargs) return result return wrapper
Code language: Python (python)

The following shows the complete code:

from functools import wraps def repeat(fn): @wraps(fn) def wrapper(*args, **kwargs): for _ in range(5): result = fn(*args, **kwargs) return result return wrapper @repeat def say(message): ''' print the message Arguments message: the message to show ''' print(message) say('Hello')
Code language: Python (python)

What if you want to execute the say function repeatedly 10 times. In this case, you need to change the hard-coded value 5 in the repeat decorator.

However, this solution isn’t flexible. Suppose you want to use the repeat decorator to execute a function 5 times and another function 10 times. The repeat decorator would not meet the requirement.

To meet the requirement, the repeat decorator should accept an argument that specifies the number of times a function should execute like this:

@repeat(5) def say(message): ...
Code language: Python (python)

To define the repeat decorator, the repeat(5) should return the original decorator.

def repeat(times): # return the original "repeat" decorator
Code language: Python (python)

The new repeat function returns a decorator. And it’s often referred to as a decorator factory.

The following repeat function returns a decorator:

def repeat(times): ''' call a function a number of times ''' def decorate(fn): @wraps(fn) def wrapper(*args, **kwargs): for _ in range(times): result = fn(*args, **kwargs) return result return wrapper return decorate
Code language: Python (python)

In this code, the decorate function is a decorator. It’s equivalent to the original repeat decorator.

Note that the new repeat function isn’t a decorator. It’s a decorator factory that returns a decorator.

Put it all together.

from functools import wraps def repeat(times): ''' call a function a number of times ''' def decorate(fn): @wraps(fn) def wrapper(*args, **kwargs): for _ in range(times): result = fn(*args, **kwargs) return result return wrapper return decorate @repeat(10) def say(message): ''' print the message Arguments message: the message to show ''' print(message) say('Hello')
Code language: Python (python)

Summary

  • Use a factory decorator to return a decorator that accepts arguments.
Did you find this tutorial helpful ?