I'm trying to write a decorator that takes a few arguments, and can decorate arbitrary functions. After reading a few code examples, and stepping through the debugger I've figured out how to write it. But I don't fully understand why it works.
def bar(arg1):
def inner_bar(f):
def inner_inner_bar(*args, **kwargs):
new_args = (x + arg1 for x in args)
return f(*new_args, **kwargs)
return inner_inner_bar
return inner_bar
@bar(4)
def foo(x, y):
print("Sum is {0}".format(x+y))
if __name__ == "__main__":
foo(1, 2)
Sum is 11
What I don't fully grasp is how/why the function f exists in the scope of inner_bar but not bar. And similarly that args and kwargs exist in the scope of inner_inner_bar but not inner_bar.
What is Python doing when I use @bar that makes the different variables available in the different methods of my decorator?
What is Python doing when I use @bar that makes the different variables available in the different methods of my decorator?
Note that you're not just using @bar, you're using @bar(4). It works like this:
bar(4) returns a function (inner_bar)@bar(4) to decorate foo calls inner_bar(foo).inner_bar(foo) returns a function (inner_inner_bar)inner_inner_bar) is assigned back to the name foo
foo, you are calling inner_inner_bar, so whatever arguments you pass are passed as the *args and **kwargs
What Python is "doing" is calling the functions involved. All of the variables you're asking about (f, args and kwargs) are just function arguments, which, as usual, become available when their function is called. f becomes available when inner_bar is called, namely when you apply the decorator. *args and **kwargs become available when inner_inner_bar is called, namely when you call the decorated function. The only thing that is available when you write bar(4) is arg1, because the other functions haven't been called yet.
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