0

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

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
Sam Coutteau
  • 357
  • 2
  • 15

2 Answers2

1

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,)
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
-2

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.

NotAnAmbiTurner
  • 2,553
  • 2
  • 21
  • 44
  • That only works *inside* the function. It doesn't let you inspect the number of parameters from the outside. – Aran-Fey Oct 29 '18 at 09:21
  • Oh I get what you're saying now. I guess my (clarified) suggestion would be to write the functions you are passing to `call()` to just take all of the *args and deal with them appropriately. – NotAnAmbiTurner Oct 29 '18 at 09:22
  • Because the `call` function wants to find out how many arguments `function` accepts. – Aran-Fey Oct 29 '18 at 09:23