是否可以将这种使用字典的方法应用于 find/evaluate 众多函数之一及其相应的参数?
Is it possible to adapt this approach of using dictionaries to find/evaluate one of many functions and its corresponding 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 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))
returns 一条错误消息
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
都通过字典传递。我尝试了 adding/removing 额外括号和 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 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))
然而,这开始变得有点混乱了。我会确保您花一些时间并仔细检查这是否确实是您想要做的。
您正在尝试混合命名参数和未命名参数!
根据经验,如果您使用 ** 符号将字典传递给函数,则可以使用 **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 的解决方案,但您必须区分这两种情况。
要以最少的更改修复您的代码,请将 return func(x, args)
更改为 return func(x, *args)
。我认为这就是评论中的。
但是,我认为您的代码可以进一步简化
使用 *
("splat") 和 **
("double-splat"?) positional/keyword argument unpacking operators 像这样:
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
假设一个人有几个独立的函数来评估一些给定的数据。与其使用冗余 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))
returns 一条错误消息
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
都通过字典传递。我尝试了 adding/removing 额外括号和 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 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))
然而,这开始变得有点混乱了。我会确保您花一些时间并仔细检查这是否确实是您想要做的。
您正在尝试混合命名参数和未命名参数!
根据经验,如果您使用 ** 符号将字典传递给函数,则可以使用 **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 的解决方案,但您必须区分这两种情况。
要以最少的更改修复您的代码,请将 return func(x, args)
更改为 return func(x, *args)
。我认为这就是评论中的
但是,我认为您的代码可以进一步简化
使用 *
("splat") 和 **
("double-splat"?) positional/keyword argument unpacking operators 像这样:
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