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

Calling functions with parameters using a dictionary in Python

提问人:Ruben9922 提问时间:7/5/2014 更新时间:5/25/2017 访问量:24933

问:

我正在制作一个程序,它有一个主菜单,要求用户输入一个选项并将其存储在整数中,这在字典中可以查找。然后运行相应的函数。如果函数没有参数,则以下代码有效:option1options

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

Python 函数 字典 参数

评论


答:

22赞 jonrsharpe 7/5/2014 #1

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

评论

0赞 harryscholes 5/25/2017
这正是我需要的!顺便说一句,您在 options[2] 的值中缺少一个逗号。
9赞 icktoofay 7/5/2014 #2

确定。在 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]()

正如 jonrsharp 的回答中所详述的,您也可以使用 .正如他所指出的,这样做的好处是能够附加一些你自己的论点:functools.partiallambda

options[option1]('hello')  # adds 'hello' to previously-specified arguments

但是,如果您不需要此功能,则零参数可以很好地为您服务。lambda

评论

0赞 Ruben9922 12/19/2018
我喜欢将所有函数表示为元组的一致性。
0赞 Ruben9922 12/19/2018
将函数表示为元组(您提到的第一种方式)和使用部分函数(如@jonrsharpe的回答),一种方式是否比另一种方式更可取?
1赞 icktoofay 8/25/2019
@Ruben9922:我个人喜欢第二种方法,其中一切都只是一个功能,因为它使呼叫站点变得简单,但很难说有客观理由偏爱一个而不是另一个;他们都工作得很好。
4赞 Xirion11 9/9/2016 #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

评论

1赞 Ruben9922 9/6/2019
问题是字典中的函数采用不同数量的参数。请注意,在问题中,表示该函数不带参数(而不是参数)。""""