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

Posted

技术标签:

【中文标题】在 Python 中使用字典调用带参数的函数【英文标题】:Calling functions with parameters using a dictionary in Python 【发布时间】:2014-08-26 04:31:12 【问题描述】:

我正在制作一个程序,它有一个主菜单,要求用户输入一个选项并将其存储在整数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 语句。

【问题讨论】:

【参考方案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

【讨论】:

这正是我所需要的!顺便说一句,您在 options[2] 的值中缺少逗号。【参考方案2】:

要添加到icktoofay's answer,如果您想将参数传递给 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

【讨论】:

问题在于字典中的函数采用不同数量的参数。请注意,在问题中,"" 表示该函数不接受任何参数(而不是 "" 是一个参数)。【参考方案3】:

当然。在 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 就可以满足您的需求。

【讨论】:

我喜欢将所有函数表示为元组的一致性。 对于将函数表示为元组(您提到的第一种方式)和使用部分函数(如@jonrsharpe 的回答),一种方式比另一种方式更可取吗? @Ruben9922:我个人喜欢第二种方法,其中一切都只是一个函数,因为它使调用站点变得简单,但很难说有客观的理由偏爱其中一个。他们都工作正常。

以上是关于在 Python 中使用字典调用带参数的函数的主要内容,如果未能解决你的问题,请参考以下文章

python脚本中调用执行另一个带参数python脚本的问题

参数传递:shell脚本调用一个带参数的python函数

Python,调用一个带参数默认值的函数

无法在python中调用类函数(TypeError:object()不带参数)

python 基础 11 带参数装饰器与递归函数

请教Inno Setup,带多个参数的函数调用问题