提问人:sds 提问时间:11/8/2023 最后编辑:sds 更新时间:11/9/2023 访问量:131
从给定组件以编程方式构造 python 函数
Construct a python function programmatically from given components
问:
我有一个 python 函数列表,例如,
def f1(x, a): return x + a
def f2(x, y, a, b): return x * a + y * b
def f3(c, d, e): return c * d - e
def f4(y, z): return 2 * y - z
...
my_functions = [f1, f2, f3, f4 ...]
我想以预定义的方式组合它们的所有对,例如,通过取一个产品:
my_products = [product(f,g) for f,g in itertools.combinations(my_functions, 2)]
因此,需要 2 个函数,和 ,并生成一个计算其乘积的函数:should returnproduct
f
g
product(f1,f2)
def f1_f2(x, a, y, b):
return f1(x=x, a=a) * f2(x=x, y=y, a=a, b=b)
对于Lisp,我会使用一个简单的宏。
使用 Perl,我将创建并使用 eval
的字符串表示。f1_f2
我该如何使用 Python?
编写文件并加载它?
使用 exec
?EVAL
?编译
?
PS1的。生成的函数将传递给 curve_fit
,因此所有有问题的函数(尤其是 !) 的返回值都必须采用位置参数而不是 kw dicts。product
参数函数将具有必须正确处理的相交的参数名称集。
答:
0赞
matszwecja
11/9/2023
#1
我建议重写您的函数以接受任意数量的关键字参数。然后,您可以简单地将任何任意关键字参数列表传递给这两个函数,而无需从外部知道它们的签名:
def f1(**kwargs): return kwargs['x'] + kwargs['a']
def f2(**kwargs): return kwargs['x'] * kwargs['a'] + kwargs['y'] * kwargs['b']
def f3(**kwargs): return kwargs['c'] * kwargs['d'] - kwargs['e']
def f4(**kwargs): return 2 * kwargs['y'] - kwargs['z']
def product(f, g):
def fun(**kwargs):
return f(**kwargs) * g(**kwargs)
return fun
foo = product(f1, f2)
print(foo(x = 1, y = 2, a = 3, b = 4, c = 5))
评论
1赞
MisterMiyagi
11/9/2023
如果函数需要某些参数,则这些参数不应是 kwargs 的一部分。
1赞
JonSG
11/9/2023
这也是我解决问题的方式,除非我会这样做.def f1(x, a, **kwargs): return x + a
1赞
Yevhen Kuzmovych
11/9/2023
@JonSG我什至会说更明确地说明kwargs的“一次性”性质。def f1(x, a, **_): return x + a
0赞
JonSG
11/9/2023
@YevhenKuzmovych 当然,这对我来说是完全可以接受的。我只是使用了惯例。**kwargs
0赞
Yevhen Kuzmovych
11/9/2023
#2
为此,您需要过滤每个函数的关键字参数:
def product(f, g):
def f_g(**kwargs):
f_kwargs = {k: v for k, v in kwargs.items() if k in f.__code__.co_varnames}
g_kwargs = {k: v for k, v in kwargs.items() if k in g.__code__.co_varnames}
return f(**f_kwargs) * g(**g_kwargs)
return f_g
my_products = [product(f,g) for f,g in itertools.combinations(my_functions, 2)]
评论
0赞
sds
11/9/2023
f_g
必须取位置参数
2赞
Yevhen Kuzmovych
11/9/2023
@sds 你怎么知道哪些位置参数去哪里?
1赞
Yevhen Kuzmovych
11/9/2023
...即你如何决定你的例子中的顺序,而不是(说)。x, a, y, b
x, y, a, b
2赞
matszwecja
11/9/2023
我觉得我们这里有一个 XY 问题。
2赞
Charles Duffy
11/9/2023
@sds,......在我读到你上面的评论之前,我当然不知道“决定而不是”是这个问题的重点。如果你写问题时只关注 Python 元编程挑战(这是一个有价值的挑战!),而不假设读者会理解 的约束并从中推断出你的需求细节,那将是有帮助的。x,a,y,b
x,y,a,b
curve_fit
2赞
MegaIng
11/9/2023
#3
假设您的所有函数都合理简单,即没有默认值且没有仅位置参数,这应该有效:
from inspect import signature, Signature
def product(f, g):
f_sig = signature(f)
g_sig = signature(g)
combined = f_sig.parameters | g_sig.parameters
f_g_sig = Signature(combined.values())
def f_g(*args, **kwargs):
bound = f_g_sig.bind(*args, **kwargs)
f_res = f(**{name: bound.arguments[name] for name in f_sig.parameters.keys()})
g_res = g(**{name: bound.arguments[name] for name in g_sig.parameters.keys()})
return f_res * g_res
f_g.__signature__ = f_g_sig
return f_g
我们使用来自两个函数的组合参数列表构造一个对象,然后使用它来绑定传入的参数。甚至应该适用于混合位置和关键字参数。为了正确使用 ,我们还设置了 (几乎没有记录的) 属性。Signature
curve_fit
__signature__
评论
0赞
sds
11/9/2023
很好,谢谢!唉,返回的函数不能腌制。有办法吗?!
0赞
MegaIng
11/9/2023
@sds 将其绑定到全局名称,并确保该函数的 and 正确。否则,您将需要提供一个自定义对象来动态构造这些函数。__name__
__qualname__
评论
eval
eval
exec
ast