In Python, I want to have a method that builds a new function from an old one.
Input : a function like f(**kwargs)
together with a tuple of pairs that takes a dictionary of keywords
Output : a new function that has the pairs from the tuple as arguments and default values.
What I have so far:
def f(**kwargs):
return 'test',kwargs['a'], kwargs['b']
def magic(f,argtuple):
arglist=",".join([str(ke)+" = "+str(va) for ke,va in argtuple])
keylist=",".join([str(ke)+" = "+str(ke) for ke,va in argtuple])
exec("def g("+arglist+"): return f("+keylist+")")
return g
It does what I want:
In [25]: f(b=4,a=3)
Out[25]: ('test', 3, 4)
In [26]: g=magic(f,(['a',1],['b',2]))
In [27]: g()
Out[27]: ('test', 1, 2)
In [28]: g(a=3,b=5)
Out[28]: ('test', 3, 5)
In [29]: import inspect
In [30]: print inspect.getargspec(f)
ArgSpec(args=[], varargs=None, keywords='kwargs', defaults=None)
In [31]: print inspect.getargspec(g)
ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=(1, 2))
However I don't want to build the string and don't want to use the exec
function. What are other ways of achieving this?
What you are looking for is functools.partial() .
import functools
def f(**kwargs):
return 'test',kwargs['a'], kwargs['b']
def magic(f, argtuple):
return functools.partial(f, **dict(argtuple))
g = magic(f, (['a',1],['b',2]))
print g() # ('test', 1, 2)
Here is a solution that also constructs the right signature. It requires a reasonably up-to-date Python since it makes use of relativly recent additions to the inspect
module and also the __signature__
special attribute.
import inspect
def build_sig(arg_tuple):
return inspect.Signature(parameters = [inspect.Parameter(
name=name, kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
default=default) for name, default in arg_tuple])
def wrap(f, arg_tuple):
sig = build_sig(arg_tuple)
def g(*args, **kwds):
bound = sig.bind(*args, **kwds)
bound.apply_defaults()
return f(**bound.arguments)
g.__signature__ = sig
return g
def f(*args, **kwds):
return(args, kwds)
g = wrap(f, (['a', 1], ['b', 7]))
print(inspect.getargspec(g))
print(g(3))
# ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=(1, 7))
# ((), {'a': 3, 'b': 7})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.