I'm learning about decorators and came across an example where the decorator took an argument. This was a little confusing for me though, because I learned that (note: the examples from this question are mostly from this article):
def my_decorator(func):
def inner(*args, **kwargs):
print('Before function runs')
func(*args, **kwargs)
print('After function ran')
return inner
@my_decorator
def foo(thing_to_print):
print(thing_to_print)
foo('Hello')
# Returns:
# Before function runs
# Hello
# After function ran
was equivalent to
foo = my_wrapper(foo)
So, it doesn't make sense to me how something could take an argument, to better explain, here is a decorator example that takes an argument:
def repeat(num_times):
def decorator_repeat(func):
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
for _ in range(num_times):
value = func(*args, **kwargs)
return value
return wrapper_repeat
return decorator_repeat
@repeat(num_times=4)
def greet(name):
print(f"Hello {name}")
greet('Bob')
# Returns:
# Hello Bob
# Hello Bob
# Hello Bob
# Hello Bob
So when I see this I am thinking:
greet = repeat(greet, num_times=4)
I know that that can't be right because num_times
is the only argument that should be getting passed. So what is the correct equivalent to @repeat(num_times=4)
without the "@
-symbol-syntax"? Thanks!
In this case it would be:
greet = repeat(num_times=4)(greet)
This would explain the two levels of nesting within repeat
(you need to call the function "twice," you could say). repeat(num_times=4)
returns a decorator, then that decorator wraps around greet
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With