2015-05-14 100 views
1

這包含在Python教程中,但我仍然不完全理解Python具有這種風格的原因。是純粹的約定,還是有一些解釋爲什麼Python有以下默認參數的風格:瞭解Python風格,函數的默認參數

我的理解是,Python更喜歡something=None而不是something=[]作爲函數的默認參數。但是...爲什麼不使用something=[]?當然,這是慣例在其他語言,如C

作爲一個例子,取這兩個例子,它們是等效

def function(arr, L=[]): 
    L.append(arr) 
    return L 

def function(arr, L=None): 
    if L is None: 
     L = [] 
    L.append(arr) 
    return L 

我的理解是,首先是「不正確的風格「。爲什麼?

編輯:啊,我終於明白了。我在上面是不正確的:這兩個函數是不等價的。當函數被定義時,默認參數會被計算一次,而不是每次函數被調用!

+4

請參閱http://docs.python-guide.org/en/latest/writing/gotchas/ –

+2

它們*可能*在每次調用該函數時都會運行一段代碼(如lambda)並創建一個*新的*空列表。但是,這將會不必要地降低性能,並且2.使記憶/緩存樣式代碼難以寫入。老實說,Python以它的方式處理默認參數是一件幸事。 – Shashank

+2

在這裏回答http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument –

回答

1

因爲當你調用函數,但是當它第一次聲明,它在模塊被解釋的說法l分配的[]的初始值。

見:Python: Common Gotcha感謝@ferhat埃爾馬斯

例子:顯示是怎麼回事

$ python 
Python 2.7.9 (default, Mar 19 2015, 22:32:11) 
[GCC 4.8.4] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> def f(L=[]): 
...  L.append(1) 
...  return id(L), L 
... 
>>> def g(L=None): 
...  L = [] if L is None else L 
...  L.append(1) 
...  return id(L), L 
... 

我們會忽略,當你在另一個列表傳遞會發生什麼到L的論點,因爲這種行爲是明確定義和可接受的。 (需要一個列表,附加到它並返回它)。

>>> f() 
(139978918901088, [1]) 
>>> g() 
(139978918964112, [1]) 

第一次我們稱之爲f()g()我們可能會誤以爲我們已經成功地從正確的初始空單返回一個新的列表?當我們再次呼籲f()相比發生了什麼什麼的正確g()

>>> f() 
(139978918901088, [1, 1]) 
>>> g() 
(139978918964112, [1]) 

所以您所指定的參數L初始值設置一次,只有只有當被定義的功能;不是在被調用時。這是一個常見的問題,正如鏈接中所解釋的。

NB:id()這裏返回對象的唯一標識,所以你可以清楚地看到,爲什麼首先是定義一個可變對象的默認值不正確的方法,如清單。

另請注意:在上述示例中,L的標識在調用f()時不會更改。

4

當您將參數設置爲列表的值時,會在函數定義時分配,而不是在調用函數時分配。這就是爲什麼使用相同的輸入參數多次調用函數會得到不同的結果。謹防!!!

def function(arr, L=[]): 
    L.append(arr) 
    return L 

arr = [1, 2, 3] 

>>> function(arr) 
[[1, 2, 3]] 

>>> function(arr) 
[[1, 2, 3], [1, 2, 3]] 
+0

這也是一個很好的答案。 – JesseTrevve

2

默認值是一個空列表,每次調用它時會引用一個特定變量,而不是每次都創建一個新的空列表。

>>> def add(defList=[]): 
     defList.append(1) 
     return defList 
>>> add() 
[1] 
>>> add() 
[1,1] 

這是Python中可變數據如何工作的怪癖。它可能偶爾有用,但通常使用None更安全。然後創建一個空列表,如果一個值沒有被傳遞。

2

原因是Python存儲的值爲L。換句話說L參考到一個常數。但是常數可以更新

你可以說,Python的把它存儲爲:

   |--> [] 
       | 
function (arr, L) 

但是[]是一個普通的對象(因此有狀態),可以和修改。現在,如果函數可以修改或返回L,則開始修改L的狀態。在這個例子中:

def function(arr, L=[]): 
    L.append(arr) 
    return L 

修改L。如果調用此第一時間(例如用function(123)),對象是如此更新,現在它被表示爲:

   |--> [123] 
       | 
function (arr, L) 

結果的function行爲取決於全局狀態。總的來說,一個全球性的國家在代碼設計上被認爲是一種難聞的氣味,而且這並不是人們所期望的。這不適用於None,因爲您修改本地參考L(不是對象本身)。

可以說對象是一樣的,但是每次調用該函數時,您都會將複製到本地變量L的引用

現在對於第二種情況:

    |--> None 
        | 
def function(arr, L): 
    if L is None: 
     L = [] 
    L.append(arr) 
    return L 

如果調用此方法,你把值賦給L,但L本身不是全球(只有對象到L指)。所以如果你調用這個方法,在if之後,函數(進行中)看起來就像。