If I have a function
def foo(x, y): pass
how can I tell, from inside the function, whether y
was passed positionally or with its keyword?
I'd like to have something like
def foo(x, y): if passed_positionally(y): print('y was passed positionally!') else: print('y was passed with its keyword')
so that I get
>>> foo(3, 4) y was passed positionally >>> foo(3, y=4) y was passed with its keyword
I realise I didn't originally specify this, but is it possible to do this whilst preserving type annotations? The top answer so far suggests using a decorator - however, that does not preserve the return type
You can get the number of arguments from the special parameter $# . Value of 0 means "no arguments". $# is read-only. When used in conjunction with shift for argument processing, the special parameter $# is decremented each time Bash Builtin shift is executed.
The command line has three parameters: one, two, and three four. Positional parameters are delimited by a space. The shell interprets the things after the spaces as individual parameters. If the parameter itself contains a space, enclose it in quotation marks, as in "three four," above.
Any number of arguments can be passed to a function. There is no limit on this. Function arguments are stored in stack memory rather than heap memory.
The main() function has two arguments that traditionally are called argc and argv and return a signed integer.
You can create a decorator, like this:
def checkargs(func): def inner(*args, **kwargs): if 'y' in kwargs: print('y passed with its keyword!') else: print('y passed positionally.') result = func(*args, **kwargs) return result return inner >>> @checkargs ...: def foo(x, y): ...: return x + y >>> foo(2, 3) y passed positionally. 5 >>> foo(2, y=3) y passed with its keyword! 5
Of course you can improve this by allowing the decorator to accept arguments. Thus you can pass the parameter you want to check for. Which would be something like this:
def checkargs(param_to_check): def inner(func): def wrapper(*args, **kwargs): if param_to_check in kwargs: print('y passed with its keyword!') else: print('y passed positionally.') result = func(*args, **kwargs) return result return wrapper return inner >>> @checkargs(param_to_check='y') ...: def foo(x, y): ...: return x + y >>> foo(2, y=3) y passed with its keyword! 5
I think adding functools.wraps
would preserve the annotations, following version also allows to perform the check over all arguments (using inspect
):
from functools import wraps import inspect def checkargs(func): @wraps(func) def inner(*args, **kwargs): for param in inspect.signature(func).parameters: if param in kwargs: print(param, 'passed with its keyword!') else: print(param, 'passed positionally.') result = func(*args, **kwargs) return result return inner >>> @checkargs ...: def foo(x, y, z) -> int: ...: return x + y >>> foo(2, 3, z=4) x passed positionally. y passed positionally. z passed with its keyword! 9 >>> inspect.getfullargspec(foo) FullArgSpec(args=[], varargs='args', varkw='kwargs', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={'return': <class 'int'>}) _____________HERE____________
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