在Python中使用字典调用带参数的函数

15 投票
3 回答
26232 浏览
提问于 2025-04-18 12:09

我正在制作一个程序,它有一个主菜单,会让用户输入一个选项,然后把这个选项存储在一个整数变量 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 个回答

4

为了补充一下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
9

当然可以。在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就完全可以了。

22

我会使用 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

撰写回答