假设我有这个功能:
def f(x,y):
return x+y
如果我使用inspect.getargspec(f).args
,我会得到['x','y']
。大。
现在假设我想在运行时创建另一个函数g(a,b)
,在运行时我不知道参数名a
和b
:
def g(a,b):
return f(a,b)
有办法做到这一点吗? Lambdas几乎是正确的,除了我只能在编译时分配参数名称。
g = lambda *p: f(*p)
不知何故,我想在运行时基于列表L(例如L=['a','b']
)动态创建函数,以便inspect.getargspec(g).args == L
。
答案 0 :(得分:3)
这是一种有点hacky的方法,它首先从现有的一个修改后创建一个新函数,然后用它替换原始代码。这主要是因为types.CodeType()
调用有很多参数。我实现的Python 3版本(未显示)有些不同,因为重命名了许多function.func_code
属性,并且types.CodeType()
的调用序列稍有改变。
我从this answer得到了@aaronasterling的想法(他说他从Michael Foord的Voidspace博客中得到了这个想法,标题为Selfless Python)。它可以很容易地变成装饰者,但我不认为根据你告诉我们的预期用途有帮助。
import types
def change_func_args(function, new_args):
""" Create a new function with its arguments renamed to new_args. """
code_obj = function.func_code
assert(0 <= len(new_args) <= code_obj.co_argcount)
# the arguments are just the first co_argcount co_varnames
# replace them with the new argument names in new_args
new_varnames = tuple(list(new_args[:code_obj.co_argcount]) +
list(code_obj.co_varnames[code_obj.co_argcount:]))
# type help(types.CodeType) at the interpreter prompt for information
new_code_obj = types.CodeType(code_obj.co_argcount,
code_obj.co_nlocals,
code_obj.co_stacksize,
code_obj.co_flags,
code_obj.co_code,
code_obj.co_consts,
code_obj.co_names,
new_varnames,
code_obj.co_filename,
code_obj.co_name,
code_obj.co_firstlineno,
code_obj.co_lnotab,
code_obj.co_freevars,
code_obj.co_cellvars)
modified = types.FunctionType(new_code_obj, function.func_globals)
function.__code__ = modified.__code__ # replace code portion of original
if __name__ == '__main__':
import inspect
def f(x, y):
return x+y
def g(a, b):
return f(a, b)
print('Before:')
print('inspect.getargspec(g).args: {}'.format(inspect.getargspec(g).args))
print('g(1, 2): {}'.format(g(1, 2)))
change_func_args(g, ['p', 'q'])
print('')
print('After:')
print('inspect.getargspec(g).args: {}'.format(inspect.getargspec(g).args))
print('g(1, 2): {}'.format(g(1, 2)))
输出:
Before:
inspect.getargspec(g).args: ['a', 'b']
g(1, 2): 3
After:
inspect.getargspec(g).args: ['p', 'q']
g(1, 2): 3
答案 1 :(得分:1)
如何使用关键字参数?
>>> g = lambda **kwargs: kwargs
>>> g(x=1, y=2)
{'y': 2, 'x': 1}
>>> g(a='a', b='b')
{'a': 'a', 'b': 'b'}
类似的东西:
g = lambda **kwargs: f(kwargs.get('a', 0), kwargs['b'])
或者假设您只想使用值:
>>> g = lambda **kwargs: f(*kwargs.values())
>>> def f(*args): print sum(args)
...
>>> g(a=1, b=2, c=3)
6
在任何情况下,使用**kwargs
语法会导致kwargs
成为通过名称传递的所有参数的字典。
答案 2 :(得分:1)
我觉得你想要这样的东西:
import inspect
import math
def multiply(x, y):
return x * y
def add(a, b):
return a + b
def cube(x):
return x**3
def pythagorean_theorum(a, b, c):
return math.sqrt(a**2 + b**2 + c**2)
def rpc_command(fname, *args, **kwargs):
# Get function by name
f = globals().get(fname)
# Make sure function exists
if not f:
raise NotImplementedError("function not found: %s" % fname)
# Make a dict of argname: argvalue
arg_names = inspect.getargspec(f).args
f_kwargs = dict(zip(arg_names, args))
# Add kwargs to the function's kwargs
f_kwargs.update(kwargs)
return f(**f_kwargs)
用法:
>>> # Positional args
... rpc_command('add', 1, 2)
3
>>>
>>> # Keyword args
... rpc_command('multiply', x=20, y=6)
120
>>> # Keyword args passed as kwargs
... rpc_command('add', **{"a": 1, "b": 2})
3
>>>
>>> # Mixed args
... rpc_command('multiply', 5, y=6)
30
>>>
>>> # Different arg lengths
... rpc_command('cube', 3)
27
>>>
>>> # Pass in a last as positional args
... rpc_command('pythagorean_theorum', *[1, 2, 3])
3.7416573867739413
>>>
>>> # Try a non-existent function
... rpc_command('doesntexist', 5, 6)
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 6, in rpc_command
NotImplementedError: function not found: doesntexist
答案 3 :(得分:0)
您可以使用* args和** kwargs
假设您在运行时生成动态函数
def func():
def dyn_func(*args, **kwargs):
print args, kwargs
return dyn_func
然后可以将args用于生成的函数
f = func()
f(test=1)
会给:
() {'test': 1}
然后可以根据需要管理args