Remove all bound arguments from function signature?

356 views Asked by At

Say, we have a function foo, which takes another function bar as an argument and does something based on bar's signature, and, sadly, throws an error when bar has default arguments. I want to use foo with functions, say, bar1,bar2,...bar100, all of which have default arguments. All of the aforementioned functions are from an outer library which I cannot change. There are too many bars to rewrite each of them as a lambda statement. The only way is to remove all bound arguments from these functions. And there's exec, but I'm not that desperate yet.

I know there's a module called inspect in python which works with function signatures, I came up with the following code:

from inspect import signature
from functools import partial

def remove_default_args(func, **kwargs):
    func = partial(func, **kwargs)
    sg = signature(func)
    unbound_parameters = [p for p in sg.parameters.values() if p.default == p.empty]
    func.__signature__ = sg.replace(parameters=unbound_parameters)
    return func

Is there any better way to do this, without inspect? I ask since I know inspect is generally frowned upon, as it only changes the metadata.

1

There are 1 answers

2
chepner On BEST ANSWER

Default argument values are stored in the __defaults__ and __kwdefaults__ attributes, which are writable. You can simply set them "back" to None to remove all defaults.

>>> def foo(x=3, *, y=5):
...    pass
...
>>> foo()
>>> foo.__defaults__, foo.__kwdefaults__
((3,), {'y': 5})
>>> foo.__defaults__ = None
>>> foo.__kwdefaults__ = None
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required positional argument: 'x'