Python 如何在运行时使用指定的参数名创建函数?
假设我有这个函数:Python 如何在运行时使用指定的参数名创建函数?,python,function,arguments,Python,Function,Arguments,假设我有这个函数: 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) 有办法做到这一点吗?lambda几乎是正确的,只是我只能在编译时指定参数名 g = lambda *p: f(*p) 不知何故,我希望在运行时基于列表L(例如L=['a','b'])
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)
有办法做到这一点吗?lambda几乎是正确的,只是我只能在编译时指定参数名
g = lambda *p: f(*p)
不知何故,我希望在运行时基于列表L(例如
L=['a','b']
)动态创建函数,以便inspect.getargspec(g).args==L
)。使用关键字参数怎么样
>>> 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
成为按名称传递的所有参数的字典。您可以使用*args和**kwargs
假设您在运行时生成一个动态函数
def func():
def dyn_func(*args, **kwargs):
print args, kwargs
return dyn_func
然后可以在生成的函数中使用args
f = func()
f(test=1)
将提供:
() {'test': 1}
然后就可以按照您的意愿管理args了我感觉您需要这样的东西:
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
位置参数
... rpc_命令('add',1,2)
3.
>>>
>>>#关键字args
... rpc_命令('multiply',x=20,y=6)
120
>>>#关键字args作为kwargs传递
... rpc_命令('add',**{“a”:1,“b”:2})
3.
>>>
>>>#混合args
... rpc_命令('multiply',5,y=6)
30
>>>
>>>#不同的arg长度
... rpc_命令('cube',3)
27
>>>
>>>#作为位置参数传入最后一个
... rpc_命令(‘勾股定理’,*[1,2,3])
3.7416573867739413
>>>
>>>#尝试一个不存在的函数
... rpc_命令('doesntexist',5,6)
回溯(最近一次呼叫最后一次):
文件“”,第2行,在
rpc_命令中第6行的文件“”
未实现错误:未找到函数:doesntexist
这里有一种有点老套的方法,它首先通过修改从现有函数创建一个新函数,然后用它替换原来的代码。这主要是因为
types.CodeType()
调用有太多参数。Python3版本有些不同,因为许多函数.func_code
属性被重命名,并且类型.CodeType()的调用顺序略有改变
我是从@aaronasterling那里得到这个想法的(他说他是从MichaelFoord的名为。它可以很容易地做成一个装饰器,但根据你告诉我们的预期用途,我不认为这有什么帮助
import sys
import types
def change_func_args(function, new_args):
""" Create a new function with its arguments renamed to new_args. """
if sys.version_info[0] < 3: # Python 2?
code_obj = function.func_code
assert(0 <= len(new_args) <= code_obj.co_argcount)
# The arguments are just the first co_argcount co_varnames.
# Rreplace them with the new argument names in new_args.
new_varnames = tuple(new_args[:code_obj.co_argcount] +
list(code_obj.co_varnames[code_obj.co_argcount:]))
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)
else: # Python 3
code_obj = function.__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(new_args[:code_obj.co_argcount] +
list(code_obj.co_varnames[code_obj.co_argcount:]))
new_code_obj = types.CodeType(code_obj.co_argcount,
code_obj.co_posonlyargcount,
code_obj.co_kwonlyargcount,
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)
modified = types.FunctionType(new_code_obj, function.__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)))
导入系统
导入类型
def change_func_参数(函数、新参数):
“”“创建一个新函数,将其参数重命名为新参数。”“”
如果sys.version_info[0]<3:#Python 2?
code_obj=function.func_代码
断言(0不确定我是否理解了这个问题。我猜你可以使用eval
语句创建lambda
。。你能给出一个在运行时创建的函数的例子吗?你可以使用FunctionType
和CodeType
来构造对象,但我不确定我是否明白这一点。这听起来像是XY问题-在sa中me是动态命名的变量,通常意味着询问者需要一个列表,这感觉是解决问题的错误途径。我将随机猜测,并假设您的目的是在装饰器中保留参数名称,以便使用inspect.getargspec
的文档工具提供一些有用的信息-在这种情况下,您需要module@Eric很好的猜测:)我的第一个猜测是:“如何从inspect中混淆函数args”Lolzt**kwargs
的问题是,生成的字典的键并不总是按照您传递它们的顺序。值的任意顺序意味着您的第二个示例可以很容易地将它们传递给f()
顺序错误,这在大多数情况下都很重要(尽管与显示的功能无关)。