I'm trying to access all arguments passed to a function in the decorator, including optional arguments. Consider this example:
def decorator(fn):
def wrapper(*args, **kwargs):
print 'in wrapper', args, kwargs
fn(*args, **kwargs)
return wrapper
@decorator
def myFn(arg1, arg2, arg3=None):
print 'in myFn', arg1, arg2, arg3
myFn(1,2)
myFn(1,2,3)
If I run this, I'll get:
in wrapper (1, 2) {}
in myFn 1 2 None
in wrapper (1, 2, 3) {}
in myFn 1 2 3
In the first run, since I don't specify 3 arguments, arg3 is defined as None for the purposes of myFn. But the fact that arg3 == None
is not available inside of decorator, either in args or kwargs. If I explicitly pass it to myFn, it'll show up inside the decorator, but if I use the default value, it's nowhere to be found.
Why is this? And how can it be fixed?
This is quite normal and cannot be "fixed"...
The decorator wrapper intercepts the arguments and keywords that are passed to the function: in other words, those passed by the caller of the function to the function itself.
arg3=None
is a default argument defined at the function scope. It cannot be intercepted before the function is actually called (directly or via the wrapper) because it does not exist at that point.
However, the default values are stored in the function object:
def fn(arg1,arg2,arg3=None):
pass
fn.func_defaults
-> (None,)
And you can use the following Get a function argument's default value? to map defaults to arguments... so I suppose the decorator could go to extreme lengths to print both passed and defaulted arguments. So I suppose my very first statement is not 100% correct :)
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