Reputation: 817
I cannot really tell how to use *args and **kwargs when combined with decorators and default arguments. Let me give you a MWE.
def outer(f):
def inner(*args, **kwargs):
print("args:", args)
print("kwargs:", kwargs)
return inner
@outer
def simple(x, y):
pass
Running the simple
function passing arguments in a different format. So:
Running:
simple(10, 20)
args: (10, 20)
kwargs: {}
Running:
simple(x=10, y=20)
args: ()
kwargs: {'x': 10, 'y': 20}
Running:
simple(10, y=20)
args: (10,)
kwargs: {'y': 20}
All of these seem to be expected. What I cannot understand is if I define the simple
function with a default value something like:
@outer
def simple(x, y=100):
pass
If I then run simple(10)
I would have expected the outcome to be:
args: (10,)
kwargs: {'y': 100}
but I get
args: (10,)
kwargs: {}
instead. Probably my understanding is not that good, so how could I achieve the expected result?
Upvotes: 3
Views: 968
Reputation: 1778
Facing the same issue and following @madbird answer, here's a snippet of a decorator that is aware of the kwargs
defaults for the function it wraps:
def outer(f):
signature = inspect.signature(f)
default_kwargs = {
kw: value.default for kw, value in signature.parameters.items() if value.default != inspect.Signature.empty
}
@wraps(f)
def inner(*args, **kwargs):
print("args:", args)
print("kwargs:", default_kwargs | kwargs)
return inner
It inspects the signature of the func it wraps, extracts all parameters with a default value (those whose default isn't a Signature.empty
) to a dict and then applies it with the provided kwargs
of the wrapped function in-order.
(Tested in Python 3.9)
Upvotes: 1
Reputation: 1379
In this case **kwargs
is not about the function signature, it's about how you called it.
And your call
simple(10)
have only specified one positional argument.
Decorator (wrapper) knows nothing about the function and its default arguments. It just passes the arguments it received further.
simple(*(10,), **{})
If you want to do some excercise and write decorator that is informed about the defaults of a function it is wrapping, I suggest to take a look at inspect.signature()
.
Upvotes: 2