Reputation: 1906
All the tutorials I find on decorators suggest using *args, **kwargs
in the wrapping function's signature, to handle arguments from the wrapped function. Yet kwargs are not working, while plain args are:
from functools import wraps
def wrapper(a_thing):
@wraps(a_thing)
def do_thing(*args, **kwargs):
print('before')
print(kwargs)
value = a_thing(*args, **kwargs)
print("after", *args, **kwargs)
return value
return do_thing
@wrapper
def output(*args, **kwargs):
print('during', *args, **kwargs)
import pdb; pdb.set_trace()
Here's my interactive output:
(Pdb) output(99, 100)
before
{}
during 99 100
after 99 100
(Pdb) output(arg1=99, arg2=100)
before
{'arg1': 99, 'arg2': 100}
*** TypeError: 'arg1' is an invalid keyword argument for this function
(Pdb)
Here's an example of one of many such tutorials:
What's the point of using **kwargs if it doesn't work? I feel like I'm missing something.
Upvotes: 2
Views: 245
Reputation: 155477
You don't want to unpack in the calls to print
; print
only accepts a limited number of keyword arguments, and will reject all others. Presumably you just want to see what was passed, so print the raw tuple
and dict
without unpacking:
def wrapper(a_thing):
@wraps(a_thing)
def do_thing(*args, **kwargs):
print('before')
print(kwargs)
value = a_thing(*args, **kwargs)
print("after", args, kwargs) # Removed unpacking
return value
return do_thing
@wrapper
def output(*args, **kwargs):
print('during', args, kwargs) # Removed unpacking
The point of unpacking is that it passes the elements of a *
unpacked iterable as sequential positional arguments, and the key value pairs from a **
unpacked mapping using the keys as keyword arguments, and the values as the associated value. So when you did:
print('during', *args, **kwargs)
having called into the function with output(arg1=99, arg2=100)
, it was as if you ran:
print('during', arg1=99, arg2=100)
Neither arg1
nor arg2
are keywords accepted by print
, so it screamed at you. By removing the unpacking, the print
becomes equivalent to:
print('during', (), {'arg1': 99, 'arg2': 100})
which is perfectly valid (it's printing the tuple
and dict
directly, not trying to unpack).
Upvotes: 2