Additional explanation:
What I want to achieve is
call(function,(*args,*toomanyargs)) == (function(*args),*toomanyargs)
call(function_with_varargs,(*args))) == (function_with_varargs(*args))
what's the pythonic way to achieve this
Additional explanation:
What I want to achieve is
call(function,(*args,*toomanyargs)) == (function(*args),*toomanyargs)
call(function_with_varargs,(*args))) == (function_with_varargs(*args))
what's the pythonic way to achieve this
You can find out how many positional arguments a function accepts by accessing the .__code__.co_argcount
attribute:
>>> function = lambda a, b, c: a+b+c
>>> function.__code__.co_argcount
3
However, that doesn't respect varargs:
>>> function = lambda *a: a
>>> function.__code__.co_argcount
0
So the more robust solution is to use inspect.signature
:
import inspect
def call(function, args):
# count the positional arguments
params = inspect.signature(function).parameters.values()
if any(param.kind == inspect.Parameter.VAR_POSITIONAL for param in params):
arg_count = len(args)
else:
POSITIONAL_KINDS = {inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD}
arg_count = sum(1 for param in params if param.kind in POSITIONAL_KINDS)
# take as many arguments as the function accepts
remainder = args[arg_count:]
args = args[:arg_count]
return (function(*args),) + tuple(remainder)
Demo:
>>> function = lambda a, b, c: a+b+c
>>> args = range(5)
>>> call(function, args))
(3, 3, 4)
>>>
>>> function = lambda a, b, c, *d: a+b+c
>>> args = range(5)
>>> call(function, args))
(3,)
One way would be to use locals()
(Check the number of parameters passed in Python function; https://docs.python.org/3/library/functions.html#locals), and do some math in the body of each function to figure out how many args are left over (unused). You can then return a result which includes a tuple of the unused arguments.