Listing variables expected by a function in Python?

function, metaprogramming, python, variables

Solution

You can use either the `inspect.signature()` or `inspect.getfullargspec()` functions:

import inspect

argspec = inspect.getfullargspec(somefunction)
signature = inspect.signature(somefunction)

`inspect.fullargspec` returns a named tuple with 7 elements:

- A list with the argument names

- The name of the catchall `*args` parameter, if defined (`None` otherwise)

- The name of the catchall `**kwargs` parameter, if defined (`None` otherwise)

- A tuple with default values for the keyword arguments; they go with the last elements of the arguments; match these by length of the default values tuple.

- A list of keyword-only parameter names

- A dictionary of default values for the keyword-only parameter names, if any

- and a dictionary containing the annotations

With `inspect.signature()` you get a `Signature` object, a rich object that models not only the above data as a more structured set of objects but also lets you bind values to parameters the same way a call to the function would.

Which one is better will depend on your use cases.

Demo:

>>> import inspect
>>> def foo(bar, baz, spam='eggs', *monty, python: "kwonly", spanish=42, **inquisition) -> "return annotation":
...     pass
... 
>>> inspect.getfullargspec(foo)
FullArgSpec(args=['bar', 'baz', 'spam'], varargs='monty', varkw='inquisition', defaults=('eggs',), kwonlyargs=['python', 'spanish'], kwonlydefaults={'spanish': 42}, annotations={'return': 'return annotation', 'python': 'kwonly'})
>>> signature = inspect.signature(foo)
>>> signature
<Signature (bar, baz, spam='eggs', *monty, python: 'kwonly', spanish=42, **inquisition) -> 'return annotation'>
>>> signature.parameters['python'].kind.description
'keyword-only'
>>> signature.bind('Eric', 'Idle', 'John', python='Cleese')
<BoundArguments (bar='Eric', baz='Idle', spam='John', python='Cleese')>

If you have a dictionary named `values` of possible parameter values, I'd use `inspect.signature()` and use the `Signature.parameters` mapping to match names:

posargs = [
    values[param.name]
    for param in signature.parameters.values()
    if param.kind is Parameter.POSITIONAL_ONLY
]
skip_kinds = {Parameter.POSITIONAL_ONLY, Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD}
kwargs = {
    param.name: values[param.name]
    for param in signature.parameters.values()
    if param.name in values and param.kind not in skip_kinds
}

The above gives you a list of values for the positional-only parameters, and a dictionary for the rest (excepting any `*args` or `**kwargs` parameters).

Problem

I am wondering if it is possible to list the variables expected by a Python function, prior to calling it, in order to pass the expected variables from a bigger dict containing a lot of variables. I have searched the net but couldn't find anything. However, the python interpreter can show the list of expected variables, so there surely must be some way to do it in a script?

Original source