Python 3.x 是否可以采用这种使用字典查找/计算众多函数之一及其相应参数的方法?
假设有几个单独的函数来计算某些给定的数据。与其使用冗余的if/else循环,不如使用字典键来查找特定函数及其相应的参数。我觉得这是可能的,但我不知道该怎么做。作为一个简化的例子(我希望适应我的情况),请考虑下面的代码:Python 3.x 是否可以采用这种使用字典查找/计算众多函数之一及其相应参数的方法?,python-3.x,function,dictionary,error-handling,args,Python 3.x,Function,Dictionary,Error Handling,Args,假设有几个单独的函数来计算某些给定的数据。与其使用冗余的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 fun
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
返回错误消息
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_one
和args_two
(定义见pick_function
)中添加/删除额外括号和副词的各种组合。这种方法是否富有成效?是否有其他方便的(在可读性和速度方面)方法不需要很多if/else循环 如果我理解你的要求,我不知道你想用1,2。。。不管怎样,你的字典都是这么写的。可以将函数名和要使用的参数列表直接传递给函数,并按如下方式使用:
def use_function(func, argList):
return (func(*argList))
print(use_function(func_one, [5, 1, 2, 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))
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
然而,这开始有点令人困惑。我会确保你花一些时间,只是仔细检查一下,这实际上是你想要做的 您正在尝试混合命名参数和未命名参数
根据经验,如果使用**表示法将dict传递给函数,则可以使用**kwargs值访问参数。但是,如果使用*notation向函数传递元组,则可以使用*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的解决方案,但您必须区分这两种情况。要以最小的更改修复代码,请将return func(x,args)
更改为return func(x,*args)
。我想这就是评论中的内容
但是,我认为您的代码可以通过
使用*
(“splat”)和**
(?)位置/关键字如下:
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))
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
尝试将其更改为:return func(x,args)(等于变量的解包)您是要放置splat运算符吗?它已经以你评论的形式出现了。我可以在大约一个小时内尝试一下,然后玩一下,谢谢。我尝试这种方法是因为我比较了具有相同最小误差度量函数(例如:卡方和最大似然估计)的多个数据集,每个数据集具有不同的可输入参数。尽管我一直对其他方法很好奇,如果我像上一个例子一样使用splat操作符,那么它会按顺序覆盖参数,对吗?如果是,这是否意味着被调用函数(func one或func_two)的所有(未初始化?)输入必须在args中?是的,*运算符按顺序转换args。**运算符根据关键字转换它们,因此顺序无关紧要。如果您提前知道args的名称,您可以使用**,或者其他方式,是的,您需要将它们放入*args中并以这种方式解包@如果你想这样做,达里斯卡似乎有一个很好的答案。另外,这里有一个很好的答案解释了*和**符号:我需要理解btwn args和kwargs的区别。这很有启发性,谢谢。因此,如果我想要一些参数而不是其他参数(例如:c在函数_one中是不允许的输入),那么KWARG就是最好的选择(因为它们基本上被命名为变量/参数)。是吗?@mikey是的,这是最安全的方法。这似乎是最简单的解决方案。如果你不介意的话,我明天会问一些相关的后续问题。