简体   繁体   English

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

[英]Calling functions with parameters using a dictionary in Python

I'm making a program which has a main menu that asks the user to input an option and store it in integer option1 , which is looked up in dictionary options . 我正在创建一个程序,其中有一个主菜单,要求用户输入一个选项并将其存储在整数option1 ,这将在字典options中查找。 The corresponding function is then run. 然后运行相应的功能。 The following code works if the functions have no parameters: 如果函数没有参数,则以下代码有效:

options = {0 : FunctionZero,    # Assign functions to the dictionary
            1 : FunctionOne,
            2 : FunctionTwo,
            3 : FunctionThree}

options[option1]()    # Call the function

If the functions have parameters the above code doesn't work as the () part assumes the functions have no parameters, but I tried the following, which stores the functions' names and parameters in tuples within the dictionary: 如果函数有参数,上面的代码不起作用,因为()部分假设函数没有参数,但我尝试了以下内容,它将函数的名称和参数存储在字典中的元组中:

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])

This code seems to work fine, but I was wondering if there's a better way to do this, especially if the functions require several parameters? 这段代码似乎工作正常,但我想知道是否有更好的方法来做到这一点,特别是如果函数需要几个参数? In other languages like C# I'd probably use a switch or case statement (which is not in Python) and I'm avoiding using if...elif statements for this. 在像C#这样的其他语言中,我可能会使用switch或case语句(不在Python中),而且我正在避免使用if...elif语句。

I would do this using functools.partial to specify the arguments when the dictionary is created: 我会使用functools.partial来指定创建字典时的参数:

from functools import partial

options = {0: FunctionZero,   
           1: FunctionOne,    
           2: FunctionTwo,
           3: partial(FunctionThree, True)} 

Note that this also allows additional parameters to be passed when the function is called (as long as all the functions in the dictionary have the same parameters missing after partial has been called): 请注意,这也允许在调用函数时传递其他参数(只要字典中的所有函数在调用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

Sure. 当然。 In Python, functions can take positional or keyword arguments. 在Python中,函数可以采用位置或关键字参数。 For most functions, arguments can be passed in either way, but that's not necessarily the case for all functions, so we do need to keep them separate. 对于大多数函数,参数可以以任何一种方式传递,但对于所有函数都不一定如此,因此我们需要将它们分开。 Positional arguments are in an iterable (often list or tuple), and keyword arguments are in a dictionary from strings to values. 位置参数位于可迭代(通常是列表或元组)中,关键字参数位于从字符串到值的字典中。

We could then represent each function as a tuple of function, positional arguments, and keyword arguments: 然后,我们可以将每个函数表示为函数,位置参数和关键字参数的元组:

options = {
    0: (function_zero, [], {}),
    1: (function_one, [], {}),
    2: (function_two, [], {}),
    3: (function_three, [True], {}),
    4: (function_four, [], {'kwarg': True}),  # takes a keyword argument
}

Then you could call them like this: 然后你可以像这样打电话给他们:

func, args, kwargs = options[option1]
func(*args, **kwargs)

But if you're always going to just pass in a constant, there's a better way: just create little no-argument wrappers for each function that call the function how you want it to be called : 但是如果你总是要传递一个常量,那么有一个更好的方法:只需为调用函数的每个函数创建几个无参数包装器, 如何调用

options = {
    0: function_zero,
    1: function_one,
    2: function_two,
    3: lambda: function_three(True),
    4: lambda: function_four(kwarg=True),
}

Then use your first method: 然后使用你的第一种方法:

options[option1]()

As detailed in jonrsharpe's answer, you can also use functools.partial rather than a lambda . 正如jonrsharpe的回答中所详述,您也可以使用functools.partial而不是lambda As he notes, this has the advantage of being able to append some of your own arguments: 正如他所指出的,这具有能够附加一些你自己的论点的优点:

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

If you don't need this functionality, though, a zero-parameter lambda will serve you just fine. 但是,如果您不需要此功能,零参数lambda将为您提供良好的服务。

To add to icktoofay's answer , if you want to pass an argument to the lambda just do the following: 要添加到icktoofay的答案 ,如果要将参数传递给lambda,请执行以下操作:

def printDouble( number ):
    print number * 2

options = {
    1: lambda num: printDouble(num)
}

options[1](4)    #this prints 8

By adding the parameter for lambda before the ":" you state that the lambda receives a parameter and it is used then in the function it calls. 通过在“:”之前添加lambda参数,您声明lambda接收参数,然后在它调用的函数中使用它。

Also if you don't want to use lambdas you can use the usual way 此外,如果您不想使用lambdas,您可以使用通常的方式

def printDouble( num ):
    print num * 2

def printHalf( num ):
    print half / 2

functionDictionary = {
    'Double': printDouble,
    'Half'  : printHalf
}

functionDictionary['Double'](2)    #This prints 4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM