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