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