是否有可能适应这种使用字典来查找/评估众多函数之一及其相应参数的方法?
假设人们有几个单独的函数来评估某些给定的数据。而不是使用冗余的if/else循环,决定使用字典键来查找特定的函数及其相应的参数。我觉得这是可能的,但我无法弄清楚如何使这项工作。作为一个简单的例子(我希望能为我的情况调整),考虑下面的代码:是否有可能适应这种使用字典来查找/评估众多函数之一及其相应参数的方法?
def func_one(x, a, b, c=0):
""" arbitrary function """
# c is initialized since it is necessary in func_two and has no effect in func_one
return a*x + b
def func_two(x, a, b, c):
""" arbitrary function """
return a*x**2 + b*x + c
def pick_function(key, x=5):
""" picks and evaluates arbitrary function by key """
if key != (1 or 2):
raise ValueError("key = 1 or 2")
## args = a, b, c
args_one = (1, 2, 3)
args_two = (4, 5, 3)
## function dictionary
func_dict = dict(zip([1, 2], [func_one, func_two]))
## args dictionary
args_dict = dict(zip([1, 2], [args_one, args_two]))
## apply function to args
func = func_dict[key]
args = args_dict[key]
## my original attempt >> return func(x, args)
return func(x, *args) ## << EDITED SOLUTION VIA COMMENTS BELOW
print(func_one(x=5, a=1, b=2, c=3)) # prints 7
但是,
print(pick_function(1))
返回一条错误消息
File "stack_overflow_example_question.py", line 17, in pick_function
return func(x, args)
TypeError: func_one() missing 1 required positional argument: 'b'
显然,不所有的args
正在通过字典。我尝试过从args_one
和args_two
(如pick_function
中定义的)添加/删除额外括号和假名的各种组合。这种方法成果丰硕吗?有没有其他方便(在可读性和速度方面)的方法,不需要很多if/else循环?
要以最少的更改修复代码,请将return func(x, args)
更改为return func(x, *args)
。我觉得这是Anton vBR is suggesting的评论。
不过,我觉得你的代码可以通过 使用*
( “图示”)和**
进一步简化位置/关键字argument unpacking operators像这样("double-splat"?):
def func_one(x, a, b, c=0):
""" arbitrary function """
# c is initialized since it is necessary in func_two and has no effect in func_one
return a*x + b
def func_two(x, a, b, c):
""" arbitrary function """
return a*x**2 + b*x + c
def func(key, *args, **kwargs):
funcmap = {1: func_one, 2: func_two}
return funcmap[key](*args, **kwargs)
def pick_function(key, x=5):
""" picks and evaluates arbitrary function by key """
argmap = {1: (1, 2, 3), 2: (4, 5, 3)}
return func(key, x, *argmap[key])
print(func_one(x=5, a=1, b=2, c=3))
# 7
print(pick_function(1))
# 7
print(func(1, 5, 1, 2, 3))
# 7
print(func(1, b=2, a=1, c=3, x=5))
# 7
这似乎是那些张贴的最简单的解决方案。如果您不介意,我会在明天提出一些相关的后续问题。 – mikey
如果我明白你在问什么,我不知道你想用1,2 ...作为你的字典键。你可以通过函数的名称,你想直接使用的功能,并使用它的方式像args来列表:
def use_function(func, argList):
return (func(*argList))
print(use_function(func_one, [5, 1, 2, 3]))
或:
def use_function_2(func, argDict):
return (func(**argDict))
print(use_function_2(func_one, {'a':1, 'b':2,'x':5, 'c':3}))
,如果你喜欢你仍然可以使用字典来保存与功能相对应的数字。这将是这样的:
def pick_function_2(key, x=5):
""" picks and evaluates arbitrary function by key """
if key != (1 or 2):
raise ValueError("key = 1 or 2")
## args = a, b, c
args_one = [1, 2, 3]
args_two = [4, 5, 3]
## function dictionary
func_dict = dict(zip([1, 2], [func_one, func_two]))
## args dictionary
args_dict = dict(zip([1, 2], [args_one, args_two]))
## apply function to args
func = func_dict[key]
args = args_dict[key]
return func(*([x] + args))
print(pick_function_2(1))
然而,这开始变得有点混乱。我会确保你花一些时间,并仔细检查,这实际上是你想要做的。
我可以在大约一个小时内尝试一下并感谢它。我正在尝试这种方法,因为我正在比较具有相同可最小化错误度量标准函数的多个数据集(例如:chi square和mle),每个数据集都有不同的可输入参数。尽管我总是对替代方法感到好奇。 – mikey
如果我像上一个例子那样使用splat运算符,那么它会按顺序覆盖这些参数,是否正确?如果是这样,这是否意味着被调用函数(func-one或func_two)的所有(非初始化?)输入都必须在args中? – mikey
是的,*运算符依次转换参数。 **运算符根据关键字转换它们,所以顺序无关紧要。如果您提前知道参数的名称,您可以使用**,否则,是的,您需要将它们放入*参数中并将它们解压缩。 @darioSka似乎有一个很好的答案,如果这是你想要做的。或者如果你想混合起来。 – wsad597
您正在尝试混合命名参数和未命名的参数!作为经验法则,如果您使用**符号将函数传递给函数,则可以使用** kwargs值访问参数。但是,如果使用*表示法将元组传递给函数,则可以使用* args值访问参数。
我通过以下方式编辑的方法:
def func_one(*args, **kwargs):
""" arbitrary function """
# c is initialized since it is necessary in func_two and has no effect in func_one
if args:
print("args: {}".format(args))
x, other_args, *_ = args
a, b , c = other_args
elif kwargs:
print("kwargs: {}".format(kwargs))
x, a , b , c = kwargs['x'], kwargs['a'], kwargs['b'], kwargs['c']
return a*x + b
所以,在第一次调用您有:
print(func_one(x=5, a=1, b=2, c=3)) # prints 7
kwargs: {'b': 2, 'a': 1, 'x': 5, 'c': 3}
7
由于您所传递命名的参数。
在第二个执行,你必须:
print(pick_function(1))
args: (5, (1, 2, 3))
7
我知道你想找到一个解决方案,而if/else语句,但你必须theese两种情况之间进行区分。
尝试将其更改为:**返回func(x,* args)**(*等于开箱变量) –
您是否想要放置一个摔跤运算符?它已经以你评论的形式出现了。 – mikey