2015-11-05 62 views
7

如果我不知道有多少參數的函數將被傳遞,我可以使用參數包裝編寫函數:爲什麼使用packed * args/** kwargs而不是傳遞list/dict?

def add(factor, *nums): 
    """Add numbers and multiply by factor.""" 
    return sum(nums) * factor 

或者,我可以通過號碼列表爲避免爭論包裝參數:

def add(factor, nums): 
    """Add numbers and multiply by factor. 

    :type factor: int 
    :type nums: list of int 
    """ 
    return sum(nums) * factor 

是否有優勢,使用參數在路過號碼列表包裝*args?或者在哪種情況下更合適?

+2

因此,您不必*有*首先通過結構。 –

+1

觀察調用語法。選擇一個你喜歡的任務。 –

+0

@ IgnacioVazquez-Abrams這有什麼優勢?圍繞論點放置括號一樣容易。 – DBedrenko

回答

5

*args/**kwargs有其優點,一般在希望能夠傳遞解壓縮數據結構的情況下,同時保留使用壓縮數據結構的能力。 Python 3的print()就是一個很好的例子。

print('hi') 
print('you have', num, 'potatoes') 
print(*mylist) 

對比的是什麼它會像如果print()只用了一個打包的結構,然後在函數內擴展它:

print(('hi',)) 
print(('you have', num, 'potatoes')) 
print(mylist) 

在這種情況下,*args/**kwargs進來非常方便。

當然,如果您希望函數始終傳遞數據結構中包含的多個參數(如sum()str.join()),那麼忽略*語法可能更有意義。

1

關於API:* args提供了一個更好的接口,因爲它聲明該方法接受任意數量的參數,就是這樣 - 沒有進一步的假設。您肯定知道該方法本身不會對包含各種參數的數據結構做任何其他操作,並且不需要特殊的數據結構。

理論上,您也可以接受一個值設置爲None的字典。爲什麼不?這是開銷和不必要的。對我來說,接受可變參數時接受一個列表會增加開銷。 (作爲其中一條評論指出)

此外,可變參數是保證調用者和被調用函數之間一致性和良好契約的好方法。不能做出任何假設。

如果你需要一個列表,那麼你知道你需要一個列表!請注意f(* args)與f(list)不一樣:第二個想要一個列表,第一個需要任意數量的參數(包括0)。好了,讓我們定義第二個作爲可選參數:

def f(l = []): pass 

酷,現在你有兩個問題,因爲你必須確保你不要修改參數L:default parameter values。是什麼原因?因爲你不喜歡*參數。 :)

PS:我認爲這是動態語言最大的缺點之一:你不再看到界面,但是!有一個界面!

+0

最後一個例子有些人爲設計,因爲它通常用'def f(l = None)來解決:l = l或[]'... – deceze

+0

爲什麼你會這樣做,當你可以使用*參數?這纔是重點。我提供了一個不好的函數簽名,我還必須修復它?這是解決設計問題的樣板代碼。 – Markon

+0

我認爲這些問題是無關的。如果你想提供一個可變的函數簽名,'* args'是最直接的方法。如果你想提供一個單一的參數列表簽名,「無」是做到這一點的方法。你不用通過使用完全不同的簽名'f(* args)'來修改簽名爲'f(l:list = None)'的函數。你希望你的API看起來像第一,如何最好地實現它第二。 – deceze

相關問題