aaronlyy
aaronlyy

Reputation: 45

Create dictionary from/with function arguments as keys and default values as value

I want to get a dictionary from a function that has the function arguments as keys and the default values as values.

I used inspect.getfullargspec() to get a list of the argument and a list of the default values. Then I tried to use dict(zip()) to create a dictionary of those lists. This works, but only if every arguments has a default value. If one has no default, everything gets mixed up (as expected).

How can I for example if a argument has no default, add a None as value. Or any other ideas?

Here's the code:

def fn(name, age=18):
    pass

spec = getfullargspec(fn)
args = spec.args
defaults = spec.defaults

zipped = dict(zip(args, defaults))

Upvotes: 3

Views: 805

Answers (1)

Carcigenicate
Carcigenicate

Reputation: 45750

Since the non-default parameters must always be on the left (because non-defaulting parameters can't come after defaulting ones), you can calculate how much padding you need, then add that on to the front of the defaults:

def func(a, b=1, c=2, *args, **kwargs):
    pass

spec = getfullargspec(func)
padded_defaults = (None,) * (len(spec.args) - len(spec.defaults)) + spec.defaults

zipped = dict(zip(spec.args, padded_defaults))  # {'a': None, 'b': 1, 'c': 2}

(len(spec.args) - len(spec.defaults)) calculates how much left padding is required then generates that padding using "sequence multiplication" ((None,) *). + spec.defaults then concatenates the padding onto the left of the existing defaults.

This may break in some corner case; although I can't think of such a case off-hand. This also isn't very efficient due to the tuple concatenation, but that's likely not an issue in 99% of cases.

There does not seem to be a mapping between arg->default stored anywhere, so it seems like your best bet is inferring what arguments have what defaults based on the number of each.

Upvotes: 3

Related Questions