Lan*_*ton 4 python lambda anonymous-function variadic-functions
我正在创建一个方法来构造一个匿名方法来返回多个变量的函数,例如f(x,y,z)= b.我希望用户能够传递变量列表:
def get_multivar_lambda(expression, variables=["x"])
Run Code Online (Sandbox Code Playgroud)
然后我希望返回的匿名函数采用精确的len(variables)参数(基于列表索引的位置或基于列表中字符串的关键字).我知道我可以使用*args和检查长度,但这似乎不优雅.
这可能吗?我怎么能这样做?
这是我如何为一个变量(其中seval是一个来自模块simple_eval)的例子:
def get_lambda(expression, variable="x"):
return lambda arg: seval(expression.replace(variable, str(arg)))
Run Code Online (Sandbox Code Playgroud)
这是我如何通过检查arguments*传递的长度来做到的:
def get_multivar_lambda(expression, variables=["x"]):
def to_return(*arguments):
if len(variables) != len(arguments):
raise Exception("Number of arguments != number of variables")
for v, a in zip(variables, arguments):
expression.replace(v, a)
return seval(expression)
return to_return
Run Code Online (Sandbox Code Playgroud)
编辑:我从用户输入中获取表达式和变量,因此一种安全的方法是最好的.
如果你可以使用Python 3,那么新引入的(Python的3.3+)inspect.Signature和inspect.Parameter可以使你的代码非常干净(PEP 362 -函数签名的对象).这些在装饰器中也非常方便:
from inspect import Parameter, signature, Signature
def get_multivar_lambda(expression, variables=["x"]):
params = [Parameter(v, Parameter.POSITIONAL_OR_KEYWORD) for v in variables]
sig = Signature(params)
def to_return(*args, **kwargs):
values = sig.bind(*args, **kwargs)
for name, val in values.arguments.items():
print (name, val)
to_return.__signature__ = signature(to_return).replace(parameters=params)
return to_return
Run Code Online (Sandbox Code Playgroud)
演示:
>>> f = get_multivar_lambda('foo')
>>> f(1)
x 1
>>> f(1, 2)
Traceback (most recent call last):
File "<pyshell#43>", line 1, in <module>
...
raise TypeError('too many positional arguments') from None
TypeError: too many positional arguments
>>> f(x=100)
x 100
Run Code Online (Sandbox Code Playgroud)
将为用户生成有用的错误消息:
>>> g = get_multivar_lambda('foo', variables=['x', 'y', 'z'])
>>> g(20, 30, x=1000)
Traceback (most recent call last):
File "<pyshell#48>", line 1, in <module>
....
TypeError: multiple values for argument 'x'
>>> g(1000, y=2000, z=500)
x 1000
y 2000
z 500
Run Code Online (Sandbox Code Playgroud)
用于内省目的的功能签名:
>>> inspect.getargspec(g)
ArgSpec(args=['x', 'y', 'z'], varargs=None, keywords=None, defaults=None)
Run Code Online (Sandbox Code Playgroud)