2014-07-04 101 views
3

我正在製作一個程序,該程序有一個主菜單,要求用戶輸入一個選項並將其存儲在整數option1中,該字符在字典options中查找。然後運行相應的功能。下面的代碼工作如果函數沒有參數:使用Python中的字典調用帶參數的函數

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語句。

回答

6

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

這正是我需要的!順便說一句,你錯過了選項[2]值的逗號。 – harryscholes

+0

@h_s好眼睛!固定,謝謝;很高興它有幫助。 – jonrsharpe

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將竭誠爲您服務就好了。

2

爲了增加icktoofay's answer,如果你想一個參數傳遞給拉姆達只要做到以下幾點:

def printDouble(number): 
    print number * 2 

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

options[1](4) #this prints 8 

通過之前添加參數拉姆達的「:」你的狀態是,拉姆達接收參數然後在它調用的函數中使用它。

此外,如果你不想使用lambda表達式可以用通常的方式

def printDouble(num): 
    print num * 2 

def printHalf(num): 
    print half/2 

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

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