Is it possible to adapt this approach of using dictionaries to find/evaluate one of many functions and its corresponding args?
假设一个有几个单独的函数来评估一些给定的数据。与其使用冗余的if/else循环,不如使用字典键来查找特定的函数及其相应的参数。我觉得这是可能的,但我不知道如何使这工作。作为一个简单的例子(我希望能适应我的情况),考虑下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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 |
但是,
1 | print(pick_function(1)) |
返回错误消息
1 2 3 | File"stack_overflow_example_question.py", line 17, in pick_function return func(x, args) TypeError: func_one() missing 1 required positional argument: 'b' |
显然,并非所有的
要用最小的更改来修复代码,请将
但是,我认为您的代码可以通过使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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值访问参数。但是,如果使用*符号将元组传递给funcion,则可以使用*args值访问参数。
我按照以下方式编辑了方法:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
所以,在第一次通话中,你有:
1 2 3 | print(func_one(x=5, a=1, b=2, c=3)) # prints 7 kwargs: {'b': 2, 'a': 1, 'x': 5, 'c': 3} 7 |
因为您正在传递命名参数。
在第二次执行中,您将拥有:
1 2 3 | print(pick_function(1)) args: (5, (1, 2, 3)) 7 |
我知道你想找到一个没有if/else的解决方案,但是你必须区分这两种情况。
如果我理解你的要求,我不知道你想用1,2…不管怎样,作为字典的键。您可以将函数名和要直接使用的参数列表传递给函数,并按如下方式使用:
1 2 3 4 | def use_function(func, argList): return (func(*argList)) print(use_function(func_one, [5, 1, 2, 3])) |
或:
1 2 3 4 | def use_function_2(func, argDict): return (func(**argDict)) print(use_function_2(func_one, {'a':1, 'b':2,'x':5, 'c':3})) |
如果你愿意的话,你还可以用字典来保存与函数对应的数字。就像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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)) |
然而,这开始变得有点令人困惑。我会确保你花点时间再仔细检查一下,这是你真正想做的。