Reputation: 105
I am looking for something i'm not sure how to accompish and can't find an answer.
Lets say I have a function with unknown number of arguments except arg2. Also arg2 doesn't have a fixed argument location:
def some_func(arg1, arg2=None, maybe_arg3=None, maybe_not_arg4=None):
# Do some stuff
Now I want to check if arg2 has been passed by the user and replace it from a decorator, eg:
def some_dec(func):
@wraps(func)
def wrapper(*args, **kwargs):
# Do some stuff
# check if arg2 is passed and replace
rv = func(*args, **kwargs)
return rv
return wrapper
If it's passed as key/value then it's no problem to get it from kwargs BUT how do I get it if it's passed to args? (Since IDK the number of arguments the function requires)
Upvotes: 2
Views: 300
Reputation: 53029
inspect.signature
should give you what you want:
def f(x, y, z, a=4):
pass
import inspect
s = inspect.signature(f)
b = s.bind_partial(2, 4, 6, 8)
'a' in b.arguments
-> True
b = s.bind_partial(2, 4, 6)
'a' in b.arguments
-> False
Note that this was introduced at Python version 3.3. On older versions inspect.getargspec
provides some of the same functionality.
So your decorator could look like:
import inspect
import functools
def nag_a(func):
sig = inspect.signature(func)
@functools.wraps(func)
def wrapper(*args, **kwargs):
if not 'a' in sig.bind_partial(*args, **kwargs).arguments:
print("You really should pass 'a', y'know.")
rv = func(*args, **kwargs)
return rv
return wrapper
def nag_a_27(func):
spec = inspect.getargspec(func)
psn = spec.args.index('a')
@functools.wraps(func)
def wrapper(*args, **kwargs):
if not 'a' in kwargs and len(args) <= psn:
print "You really should pass 'a', y'know."
rv = func(*args, **kwargs)
return rv
return wrapper
@nag_a
def f(x, y, a=None):
pass
Upvotes: 1
Reputation: 78546
You can first check the kwargs
dict for the argument, if it's missing, it's likely going to be the second argument in args
; check if args
contains more than two arguments and :
def some_dec(func):
@wraps(func)
def wrapper(*args, **kwargs):
if 'args2' in kwargs:
kwargs['args2'] = 'new value' # update value
elif len(args) > 1:
args = (args[0], 'new value') + args[2:] # rebuild args with new value
rv = func(*args, **kwargs)
return rv
return wrapper
Upvotes: 1