Parameterised Decorator in Python

Sanjeev Rohila
2 min readMay 15, 2020

So far most of have a fair idea about decorators, if not then

“Decorators are the way in python we can enhance the functionality of function, or we could say we could supercharge our functions.”

def decorator(func):
def wrapper():
print("##########")
func()
print("##########")
return wrapper
def hello():
print("Hello")
def bye():
print("Bye")

Now above two simple functions are there, they ordinarily print, “Hello” and “Bye”

>>> print("Hello")
Hello
>>> bye()
Bye
>>>

But now lets Enhance the functionality of hello and bye functions!

>>> hello_enhanced = decorator(hello)
>>>
>>> hello_enhanced()
##########
Hello
##########
>>>

But there a better way to do it

@decorator
def hello():
print("Hello")
@decorator
def bye():
print("Bye")

and then simpally

>>> hello_enhanced = decorator(hello)
>>>
>>> hello()
##########
Hello
##########
>>>

Now lets say there are some parameters , and the function accept a name and a feeling

@decorator
def hello(name, status="working"):
print("i am %s and i am %s" %(name, status))

We need to enhance the decorator to handle the params:

def decorator(func):
def wrapper(*args, **kwargs):
print("##########")
func(*args, **kwargs)
print("##########")
return wrapper
>>>
>>> hello("Steven", status="Swimming")
##########
i am Steven and i am Swimming
##########
>>>

Now let’s get to a real situation, In our test code, we want a function to be attempted 3 times, before raising an error! calling an api, connecting to a remote server using paramiko etc, then we can use parameterised decorator.

The below decorator will try to call a function, with the number of attempt and the delay in attempts

import requests
import time
def with_retries(attempts=3, delay=1):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(attempts):
print("Calling %s, "
"attempt %s" % (
func.__name__,
i))
try:
return func(*args, **kwargs)
except Exception as exc:
print("Failed with exception %s" % exc)
time.sleep(delay)
print("Failed to execute in %s attempts!" % attempts)
return wrapper
return decorator
@with_retries()
def get_api(api):
res = requests.get(api)
return res.status_code

We haven’t entered the parameters, and we want the decorator to run with the default values, otherwise we can pass the parameters to the call with desired parameters.

>>>
>>>get_api("sds")
Calling get_api, attempt 0
Failed with exception Invalid URL 'sds': No schema supplied. Perhaps you meant http://sds?
Calling get_api, attempt 1
Failed with exception Invalid URL 'sds': No schema supplied. Perhaps you meant http://sds?
Calling get_api, attempt 2
Failed with exception Invalid URL 'sds': No schema supplied. Perhaps you meant http://sds?
Failed to execute in 3 attempts!

--

--