Passing Default Arguments To A Decorator In Python
Solution 1:
Default arguments are part of the function's signature. They do not exist in the decorator call.
To access them in the wrapper you need to get them out of the function, as shown in this question.
import inspect
from functools import wraps
defget_default_args(func):
signature = inspect.signature(func)
return {
k: v.default
for k, v in signature.parameters.items()
if v.default isnot inspect.Parameter.empty
}
defmy_decorator(f):
@wraps(f)defwrapper(*args, **kwds):
print('Calling decorated function')
print('args:', args)
kwargs = get_default_args(f)
kwargs.update(kwds)
print('kwargs:', kwargs)
return f(*args, **kwds)
return wrapper
@my_decoratordefexample(i, j=0):
"""Docstring"""print('Called example function')
example(i=1)
Output:
Calling decorated functionargs: ()
kwargs: {'i': 1, 'j': 0}
Called example function
Solution 2:
You can get default argument values by using __defaults__
special attribute.
defmy_decorator(f):
@wraps(f)defwrapper(*args, **kwds):
print('def args values', f.__defaults__)
return f(*args, **kwds)
return wrapper
Reference: look for __defaults__
in https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy
A tuple containing default argument values for those arguments that have defaults, or None if no arguments have a default value
Solution 3:
Getting the exact list of args and kwargs is a little tricky, since you can pass positional args as a kwarg, or vice versa. Newer versions of python also add positional-only or keyword only arguments.
However, inspect.signature
has a mechanism which can apply defaults: calling .bind(*args, **kwargs)
followed by .apply_defaults()
. This can give you a dictionary of effectively what all the arguments are to the function. In the example in OP, this becomes:
from functools import wraps
import inspect
defmy_decorator(f):
sig = inspect.signature(f)
@wraps(f)defwrapper(*args, **kwds):
bound = sig.bind(*args, **kwds)
bound.apply_defaults()
print('Calling decorated function')
print('called with:', bound.arguments)
return f(*args, **kwds)
return wrapper
@my_decoratordefexample(i, j=0):
"""Docstring"""print('Called example function')
example(i=1)
This outputs the following on Python 3.9:
Calling decorated functioncalledwith: OrderedDict([('i', 1), ('j', 0)])
Called example function
Post a Comment for "Passing Default Arguments To A Decorator In Python"