在Python中使用字典调用带参数的函数
我正在制作一个程序,它有一个主菜单,会让用户输入一个选项,然后把这个选项存储在一个整数变量 option1
中。这个选项会在一个叫 options
的字典里查找。找到后,就会运行对应的函数。如果这些函数没有参数,下面的代码就能正常工作:
options = {0 : FunctionZero, # Assign functions to the dictionary
1 : FunctionOne,
2 : FunctionTwo,
3 : FunctionThree}
options[option1]() # Call the function
但是如果函数有参数,上面的代码就不行了,因为 ()
部分假设函数没有参数。我尝试了下面的方法,把函数的名字和参数存储在字典里的元组中:
options = {0 : (FunctionZero,""), # FunctionsZero, FunctionOne
1 : (FunctionOne,""), # and FunctionTwo have no parameters
2 : (FunctionTwo,""),
3 : (FunctionThree,True)} # FunctionThree has one parameter
if options[option1][1] == "": # Call the function
options[option1][0]()
else:
options[option1][0](options[option1][1])
这段代码看起来没问题,但我在想有没有更好的方法,特别是当函数需要多个参数的时候?在其他语言,比如C#,我可能会使用switch或case语句(但Python里没有这种语法),而且我想避免使用 if...elif
语句。
3 个回答
为了补充一下icktoofay的回答,如果你想给lambda表达式传递一个参数,可以这样做:
def printDouble( number ):
print number * 2
options = {
1: lambda num: printDouble(num)
}
options[1](4) #this prints 8
在冒号前面添加lambda的参数,这样就说明这个lambda会接收一个参数,然后在它调用的函数中使用这个参数。
另外,如果你不想使用lambda表达式,也可以用传统的方式来实现。
def printDouble( num ):
print num * 2
def printHalf( num ):
print half / 2
functionDictionary = {
'Double': printDouble,
'Half' : printHalf
}
functionDictionary['Double'](2) #This prints 4
当然可以。在Python中,函数可以接收位置参数和关键字参数。大多数函数都可以用这两种方式传递参数,但并不是所有函数都这样,所以我们需要把它们区分开来。位置参数通常放在一个可迭代的对象里(通常是列表或元组),而关键字参数则放在一个字典中,字典的键是字符串,值是对应的值。
我们可以把每个函数表示成一个元组,里面包含函数本身、位置参数和关键字参数:
options = {
0: (function_zero, [], {}),
1: (function_one, [], {}),
2: (function_two, [], {}),
3: (function_three, [True], {}),
4: (function_four, [], {'kwarg': True}), # takes a keyword argument
}
然后你可以这样调用它们:
func, args, kwargs = options[option1]
func(*args, **kwargs)
不过,如果你总是要传入一个固定的值,有更好的方法:为每个函数创建一个不带参数的小包装函数,这个包装函数会按照你想要的方式调用原函数:
options = {
0: function_zero,
1: function_one,
2: function_two,
3: lambda: function_three(True),
4: lambda: function_four(kwarg=True),
}
然后使用你之前的方法:
options[option1]()
正如jonrsharpe的回答中详细说明的,你也可以使用functools.partial
来代替lambda
。正如他提到的,这样做的好处是可以添加你自己的参数:
options[option1]('hello') # adds 'hello' to previously-specified arguments
不过,如果你不需要这个功能,使用一个零参数的lambda
就完全可以了。
我会使用 functools.partial
来指定在创建字典时的参数:
from functools import partial
options = {0: FunctionZero,
1: FunctionOne,
2: FunctionTwo,
3: partial(FunctionThree, True)}
注意,这样做还允许在调用函数时传入额外的参数(只要字典中的所有函数在调用 partial
后缺少的参数是一样的):
def test(one, two, three=None, four=None):
...
def test2(one, two, three=None):
...
options = {1: partial(test, 1, three=3, four=4),
2: partial(test2, 1, three=3)}
...
options[choice](2) # pass the 'two' argument both functions still require