Decorating functions with parameters
Can we decorate a function that has some parameters?
Of course we can. Just include the same parameters in the inner (wrapper) function.
def validator(func):
def wrapper(numerator, denominator):
try:
return func(numerator, denominator)
except ZeroDivisionError:
print("Sorry, I do not know how to divide by 0.")
return float("NaN")
return wrapper
@validator
def divide(numerator, denominator):
return numerator/denominator
answer = divide(5, 0)
print(answer)
What if you don’t care about tracking the parameters? Just use *args
and **kwargs
in the inner function, and pass them on to the function you are wrapping.
def repeat(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
func(*args, **kwargs)
return wrapper
@repeat
def greet(message, firstname, lastname):
print(f"{message}, {firstname} {lastname}!")
greet("Merry Christmas", "Josiah", "Wang")
And what if our decorator itself needs some parameters? For example, I might want to allow the decorator to repeat a function an arbitrary number of times. Well, that requires a bit more work. You will have to wrap your decorator further in another function. Don’t worry too much about this one - you will unlikely need to do this! (And my head is spinning too!)
def n_repeat(times):
def repeat(func):
def wrapper(*args, **kwargs):
for i in range(times):
func(*args, **kwargs)
return wrapper
return repeat
@n_repeat(5)
def greet(message, firstname, lastname):
print(f"{message}, {firstname} {lastname}!")
@n_repeat(3)
def sing(line):
print(line)
sing("We wish you a Merry Christmas...")
greet("Happy New Year", "Josiah", "Wang")
print(sing)
## <function n_repeat.<locals>.repeat.<locals>.wrapper at 0x7f9e0198c430>