For efficiency purposes, I don't want to use functools.partial
for this task (adds overhead when using the function). I want to redefine a function's copy defaults arguments, by name.
For the moment I have the following :
import types
# http://stackoverflow.com/questions/6527633/how-can-i-make-a-deepcopy-of-a-function-in-python
def copy_func(f, name=None, defaults=None):
return types.FunctionType(f.__code__, f.__globals__, name or f.__name__, defaults or f.__defaults__, f.__closure__)
def f(a, b, c):
return 'a = {}, b = {} and c = {}'.format(a,b,c)
i = copy_func(f, 'i', (4,5))
print(f(3,4,5))
print(i('should be a'))
Can we modify the copy_func
tool to be called like so :
i = copy_func(f, a = 4, b = 5)
i.e, using the names of arguments from the original function.
Of course, if the arguments do not exists, I hope the function would yell at me ;)
I believe you can do this:
import inspect
def copy_func(f, name=None, **defaults):
args = inspect.getfullargspec(f).args
arg_defaults = tuple(defaults.get(arg) for arg in args)
return types.FunctionType(f.__code__, f.__globals__, name or f.__name__, arg_defaults or f.__defaults__, f.__closure__)
Since we need to provide a tuple
(arg_defaults
) for the defaults to FunctionType
, we can generate this tuple
by iterating through f
's arguments and seeing which ones have a default provided in defaults
. We use defaults.get
instead of defaults[...]
because a lack of a default is given as None
to FunctionType
.
copy_func(f, 'i', a = 4, b = 5)()
results in:
'a = 4, b = 5 and c = None'
If you want the function to yell at you if defaults
contains an invalid argument, you'd need to add this explicit condition between the declarations of args
and arg_defaults
:
if not all(arg in args for arg in defaults.keys()):
raise ValueError("defaults contains invalid arguments")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With