如何创建函数 returns 函数列表的乘积函数
How to create a function that returns a function of the product of a list of functions
我想创建一个函数,该函数 return 是函数列表乘积的函数。函数列表应该是可变长度的,函数应该有不同的参数。
例如:
def f(a, b, **kwargs):
return a + b
def g(c, d, **kwargs):
return c + d
def product_function(function_list, **kwargs):
...
<create function that returns product function of functions in
function_list>
...
return <productfunction>
在上面的示例中,这将类似于:
my_function = product_function([f,g])
这应该return一个可以使用的函数就好像它被定义为:
def my_function(a, b, c, d):
return f(a, b) * g(c, d)
我想用它来遍历一系列因素组合并优化这些组合的参数,以 select 成为数据科学项目中最具预测性的组合。
您可以在 inspect
模块中的内省实用程序的帮助下完成此操作。
具体来说,我使用 inspect.signature
to find each function's positional and keyword arguments, and Signature.bind_partial
来防止位置参数和关键字参数之间的冲突。以下是结合其他功能的功能的通用实现:
import inspect
def generic_operator_function(operator_function, default_value,
function_list, **kwargs):
POSITIONALS = {inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD}
KEYWORDS = {inspect.Parameter.POSITIONAL_OR_KEYWORD,
inspect.Parameter.KEYWORD_ONLY}
# if no functions were given, return the default value
if not function_list:
return lambda: default_value
# for each function in the list, find out how many positional
# arguments it accepts. Also find out which keyword arguments
# it accepts.
arg_maps = []
kwarg_names = []
for func in function_list:
sig = inspect.signature(func)
params = sig.parameters.values()
# count the positional arguments and map them to
# parameter names
bound_args = sig.bind_partial(**kwargs).arguments
arg_map = [param.name for param in params if param.kind in POSITIONALS
and param.name not in bound_args]
arg_maps.append(arg_map)
# find the names of all keyword arguments
if any(param.kind == inspect.Parameter.VAR_KEYWORD for param in params):
kwnames = True
else:
kwnames = {param.name for param in params if param.kind in KEYWORDS}
kwarg_names.append(kwnames)
# return a function that iterates through the function_list and
# multiplies all results
def combined_func(*args, **inner_kwargs):
value = default_value
i = 0
for func, arg_map, kwnames in zip(function_list, arg_maps, kwarg_names):
# if the function takes **kwargs, pass all kwargs. Otherwise, pass
# only those that it supports.
kw_arguments = kwargs.copy()
kw_arguments.update(inner_kwargs)
if kwnames is not True:
kw_arguments = {k: v for k, v in kw_arguments.items() if k in kwnames}
# take the next batch of arguments, but only those that aren't already
# provided as keyword arguments
arg_map = [arg for arg in arg_map if arg not in kw_arguments]
numparams = len(arg_map)
arguments = args[i:i+numparams]
kw_arguments.update({arg: value for arg, value in zip(arg_map, arguments)})
# call the function
retval = func(**kw_arguments)
value = operator_function(value, retval)
i += numparams
return value
return combined_func
有了这个,你可以很容易地定义一堆类似于你的product_function
:
的函数
import operator
def product_function(*args, **kwargs):
return generic_operator_function(operator.mul, 1, *args, **kwargs)
def sum_function(*args, **kwargs):
return generic_operator_function(operator.add, 0, *args, **kwargs)
def append_function(*args, **kwargs):
return generic_operator_function(lambda x, y: x+[y], [], *args, **kwargs)
>>> my_function = product_function([f,g])
>>> my_function(1,2, 3,4)
21
>>> sum_function([f,g])(1,2, 3,4)
10
>>> append_function([f,g])(1,2, 3,4)
[3, 7]
并且它仅正确传递每个函数支持的那些关键字参数:
>>> p = product_function([f,g], a=1, c=2)
>>> p(3, 4)
24
我想创建一个函数,该函数 return 是函数列表乘积的函数。函数列表应该是可变长度的,函数应该有不同的参数。
例如:
def f(a, b, **kwargs):
return a + b
def g(c, d, **kwargs):
return c + d
def product_function(function_list, **kwargs):
...
<create function that returns product function of functions in
function_list>
...
return <productfunction>
在上面的示例中,这将类似于:
my_function = product_function([f,g])
这应该return一个可以使用的函数就好像它被定义为:
def my_function(a, b, c, d):
return f(a, b) * g(c, d)
我想用它来遍历一系列因素组合并优化这些组合的参数,以 select 成为数据科学项目中最具预测性的组合。
您可以在 inspect
模块中的内省实用程序的帮助下完成此操作。
具体来说,我使用 inspect.signature
to find each function's positional and keyword arguments, and Signature.bind_partial
来防止位置参数和关键字参数之间的冲突。以下是结合其他功能的功能的通用实现:
import inspect
def generic_operator_function(operator_function, default_value,
function_list, **kwargs):
POSITIONALS = {inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD}
KEYWORDS = {inspect.Parameter.POSITIONAL_OR_KEYWORD,
inspect.Parameter.KEYWORD_ONLY}
# if no functions were given, return the default value
if not function_list:
return lambda: default_value
# for each function in the list, find out how many positional
# arguments it accepts. Also find out which keyword arguments
# it accepts.
arg_maps = []
kwarg_names = []
for func in function_list:
sig = inspect.signature(func)
params = sig.parameters.values()
# count the positional arguments and map them to
# parameter names
bound_args = sig.bind_partial(**kwargs).arguments
arg_map = [param.name for param in params if param.kind in POSITIONALS
and param.name not in bound_args]
arg_maps.append(arg_map)
# find the names of all keyword arguments
if any(param.kind == inspect.Parameter.VAR_KEYWORD for param in params):
kwnames = True
else:
kwnames = {param.name for param in params if param.kind in KEYWORDS}
kwarg_names.append(kwnames)
# return a function that iterates through the function_list and
# multiplies all results
def combined_func(*args, **inner_kwargs):
value = default_value
i = 0
for func, arg_map, kwnames in zip(function_list, arg_maps, kwarg_names):
# if the function takes **kwargs, pass all kwargs. Otherwise, pass
# only those that it supports.
kw_arguments = kwargs.copy()
kw_arguments.update(inner_kwargs)
if kwnames is not True:
kw_arguments = {k: v for k, v in kw_arguments.items() if k in kwnames}
# take the next batch of arguments, but only those that aren't already
# provided as keyword arguments
arg_map = [arg for arg in arg_map if arg not in kw_arguments]
numparams = len(arg_map)
arguments = args[i:i+numparams]
kw_arguments.update({arg: value for arg, value in zip(arg_map, arguments)})
# call the function
retval = func(**kw_arguments)
value = operator_function(value, retval)
i += numparams
return value
return combined_func
有了这个,你可以很容易地定义一堆类似于你的product_function
:
import operator
def product_function(*args, **kwargs):
return generic_operator_function(operator.mul, 1, *args, **kwargs)
def sum_function(*args, **kwargs):
return generic_operator_function(operator.add, 0, *args, **kwargs)
def append_function(*args, **kwargs):
return generic_operator_function(lambda x, y: x+[y], [], *args, **kwargs)
>>> my_function = product_function([f,g])
>>> my_function(1,2, 3,4)
21
>>> sum_function([f,g])(1,2, 3,4)
10
>>> append_function([f,g])(1,2, 3,4)
[3, 7]
并且它仅正确传递每个函数支持的那些关键字参数:
>>> p = product_function([f,g], a=1, c=2)
>>> p(3, 4)
24