I run a decorator demo below.
def logger(func):
def inner(*args, **kwargs):
print(args)
print(kwargs)
return func(*args, **kwargs)
return inner
@logger
def foo1(a, b, c, x=2, y=1):
print(x * y)
foo1(6,7,8)
output is:
(6, 7, 8)
{}
2
Why is the dict empty? I think it should be {'x':2, 'y':1}
That's because of no kwargs
provided in a function call. And decorator logger
know nothing about that and what function will use. It is kind a "proxy" between kwargs
provided there and real call.
See examples below:
# kwargs are not provided (not redefined), function `foo1` will use default.
>>> foo1(6, 7, 8)
(6, 7, 8)
{}
2
# new kwargs are provided and passed to decorator too
>>> foo1(6, 7, 8, x=9, y=10)
(6, 7, 8)
{'x': 9, 'y': 10}
90
This is something similar to:
def foo1(a, b, c, x=2, y=1):
print(x * y)
def logger(func):
def inner(*args, **kwargs):
print(args)
print(kwargs)
return func(*args, **kwargs)
return inner
wrapped_foo1 = logger(foo1)
wrapped_foo1(6,7,8)
Or even simplified to the following, when you can clearly see the problem:
def foo1_decorated(*args, **kwargs):
print(args) # <-- here it has no chance to know that `x=2, y=1`
print(kwargs)
return foo1(*args, **kwargs)
foo1_decorated(6, 7, 8)
The problem is that the default values for arguments are filled in by the wrapped function object when you call it, because only the wrapped function knows them (they are stored in __defaults__
and __kwdefaults__
).
If you want your decorator to know about them too, you have to mimic what the wrapped function object would do.
For this task you can use the inspect
module:
from inspect import signature
def logger(func):
sig = signature(func)
def inner(*args, **kwargs):
arguments = sig.bind(*args, **kwargs) # these 2 steps are normally handled by func
arguments.apply_defaults()
print(func, "was called with", arguments)
return func(*args, **kwargs)
return inner
@logger
def foo1(a, b, c, x=2, y=1):
print(x * y)
foo1(6,7,8)
Output:
<function foo1 at 0x7f5811a18048> was called with <BoundArguments (a=6, b=7, c=8, x=2, y=1)>
2
If you want to access the arguments, read more about it in the docs.
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