Python 3.x 是否可以采用这种使用字典查找/计算众多函数之一及其相应参数的方法?

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

假设有几个单独的函数来计算某些给定的数据。与其使用冗余的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
返回错误消息

  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是的,这是最安全的方法。这似乎是最简单的解决方案。如果你不介意的话,我明天会问一些相关的后续问题。