Skip to pass arguments to decorators if you already know what a decorator is
A decorator allows the user to add functionality to an existing function without modifying its structure.
We might need a way to authenticate an API call, and only then allow some data to be returned. We can streamline the authentication process by abstracting it into a decorator function.
Consider the following function that needs to be authenticated,
def foo(user_id): # perform some DB calls # perform some DB writes pass
We can use a decorator as follows,
def authenticate(func): def wrapper(*args, **kwargs): # perform auth checks if auth: func(*args, **kwargs) else: raise Exception('not authenticated') return wrapper
And hence, authenticating
foo is as simple as,
@authenticate def foo(user_id): # perform some DB calls # perform some DB writes pass
Now that we have some knowledge of decorators, let us proceed to something more interesting. How would we pass arguments to decorators?
This is where it gets a little confusing - we will need to create a decorator factory that returns a particular decorator based on the arguments passed.
A simple use case could be when we want to call a function multiple times, but we do not want to write it in an explicit for loop, and neither do we want to use a for loop inside the function itself.
For example, we would want to call the function
foo below, 10 times:
def foo(): print("Hello World")
In this scenario, we can create a decorator factory that takes in a
number and returns a decorator that calls a function a
number of times.
def call(number): # Decorator factory def decorator(func): def wraps(*args, **kwargs): for i in range(number): func(*args, **kwargs) return wraps return decorator
And to use the decorator factory above,
@call(10) def foo(): print("Hello World")
When we call
>>> foo() Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World
Thanks for reading! Please hit me up at email@example.com for any feedback :)