2013-04-08 85 views
1

以前可能已經提到過這個問題,但我不知道如何查找答案,因爲我不確定什麼是解決問題的好方法。Python中的靈活參數

該主題是函數參數,可以用許多不同的方式在語義上表達。例如,要將文件提供給函數,可以直接提供文件,也可以提供一個字符串,即文件的路徑。要指定一個數字,你可以允許一個整數作爲參數,或者你可以允許一個字符串(數字),或者你甚至可以允許一個字符串,比如「one」。另一個例子可能是一個函數,它需要一個列表(例如數字),但爲了方便起見,它會將一個數字轉換爲包含一個元素的列表:該數字。

在Python中是否有一個或多或少標準的方法來實現這種靈活性?如果你不確定參數是什麼類型的話,它肯定會使程序的代碼複雜化,所以我的猜測是試圖將便利函數分解到一個地方,而不是分散到任何地方,但我真的不知道最好做這樣的保理。

+1

我猜測會有一些回覆說:不要那麼做!這可能是一個好建議,但仍然存在一個問題:何時需要在不同形式的語義等價對象之間進行轉換,應該在何處進行轉換?在調用函數中?這可能會導致很多重複的代碼。 – 2013-04-08 15:30:54

+0

提出的具體示例(不是我的代碼,而是由我工作的人編寫的代碼)是文件。以文件作爲參數的函數可以將字符串作爲參數(解釋爲路徑),也可以取實際文件(open()函數的結果)。 在同一代碼中出現的另一個例子是一個函數,它可以接收消息列表或單個消息。後一種情況被解釋爲與長度爲1的列表相同。 我已經給出了這些示例,因此它們可能仍然太抽象了?什麼使他們對你更具體? – 2013-04-08 15:42:09

+0

在第二個示例中,您可以使用'* args'來完全避免檢查(即使存在缺陷)。 – Bakuriu 2013-04-08 15:44:55

回答

0
  1. 不要那樣做! ;)

但是,如果你仍然想,我建議你有一箇中間類或函數處理這個給你:

僞代碼:

def printTheNumber(num): 
    print num 


def intermediatePrintTheNumber(input): 

    num_int_dict = {'one':1, "two":2 .... 
    if input.isstring(): 
     printTheNumber(num_int_dict[input]) 
    elif input.isint(): 
     printTheNumber(input) 
    else: 
     print "Sorry Dave, I don't understand you" 

如果這是pythonic我不知道,但這就是我必須要解決的問題,當然還需要對輸入進行更多的檢查以確定它是否有效。

說到你的評論,你提到語義相似性,即"one"1可能意味着同樣的事情。

你應該問這種類型的轉換在哪裏。

那麼這取決於你的系統的設計,但我可以告訴你,它不應該在一個非常簡單的原因,我叫printTheNumber相同的功能,這就是那將使功能的方式責任重大。

根據輸入的複雜性,可能是integer 1string "1"或者,在最壞的情況下,"one"或者甚至更糟"uno"|"one"|"yxi"|"ett" .. and so on。這應該由一個函數來處理,該函數只有處理映射的數據庫纔有責任。

我會分裂它,讓我有一個函數處理字符串「一」,「兩」...等等,一個處理整數,並有第三個函數,檢查輸入,看看它是否可以轉換爲整數或不。

在我看來,有一個在設計一個fundamental缺陷警告,如果你要採取措施,對這種複雜的,但你似乎是意識到這一點,所以我不會去左右對它。

0

一個很好的方法來分解出幾個函數的共同代碼是decorators。例如,

from functools import wraps 

def takes_list(func): 
    @wraps(func) 
    def wrapper(arg): 
     if not isinstance(arg, list): 
      arg = [arg] 
     return func(arg) 
    return wrapper 

@takes_list 
def my_func(x): 
    "Does something with list x." 

我要指出,對於案件,如文件,你不希望在Python的鴨打字的方式來獲得:做一個檢查isinstance(arg, file)有它不會允許文件級的問題喜歡的東西如io.StringIO。相反,檢查str(或basestring)或甚至讓open檢查你,除了嘗試除外。

但是,通常情況下最好的做法是讓調用者將他們喜歡的內容傳遞給該函數,如果該函數無效則失敗。

+0

關於你採取了錯誤的「方向」的文件。你通常希望執行'str - > file'轉換,而不是相反,因此你應該檢查對象是否是'str'而不是'file'。此外,'open' **會檢查參數的類型,因此執行'isinstance(file,str):file = open(file)'不會消除方法的靈活性。 – Bakuriu 2013-04-08 15:48:50

+0

@Bakuriu好點。我已經編輯了我的答案,包括檢查'str'而不是'file',還提到了EAFP使用'open'的方式。 – 2013-04-08 16:11:14

-1
  1. 既然你不能添加在運行時的方法來內建類,如intstr你會作出一個開關case語句狀結構由丹尼爾·菲格羅亞提及。

  2. 另一種方法是隻轉換:

    def func(i): 
        if not isinstance(i, int): 
         i = int(i) # objects can overwrite __int__ if needed. 
    
  3. 如果你有自己的類,你可以添加方法,你可以使用雙派遣做同樣的事情你。 Smalltalk將此用於整數浮點型轉換。

  4. 另一種方法是使用對此我還沒有找到一個實現尚未面向主題的節目,但我想:https://gist.github.com/niccokunzmann/4971938

+0

'既然你不能擴展內建類,比如int或str',那麼你的想法是什麼? – 2013-04-08 15:43:34

+1

您是否使用「extend」表示「在運行時添加方法」或通過子類繼承? – Bakuriu 2013-04-08 15:46:29

+0

Smalltalk,Ruby - 在運行時添加方法 - 添加了這個 – User 2013-04-08 15:46:44

0

沒有,沒有更多或更少的「標準」的方式來這。