2009-10-18 76 views
24

夥計們,我剛開始蟒蛇最近和感到困惑與可選參數,說我有一個這樣的程序:Python的可選參數

class B: 
    pass 

class A: 
    def __init__(self, builds = B()): 
     self.builds = builds 

如果我創建一個兩次

b = A() 
c = A() 

和打印他們建立

print b.builds 
print c.builds 

我發現他們使用的是完全相同的對象,

<__main__.B instance at 0x68ee0> 
<__main__.B instance at 0x68ee0> 

但它不是我想要的,因爲如果b改變建立的一些內部狀態,一個在c對象也隨之發生變化。

是否有可能通過使用此可選參數語法每次重新創建此可選參數?

+15

如果解決了問題,您應該接受答案!幾個答案似乎非常豐富。儘管這個問題還很陳舊,但我認爲給出一個批准的答覆是一個好主意 – eipxen 2011-11-29 18:31:45

+0

[[Python中的「最小的驚訝」:可變的默認參數]可能的重複(http://stackoverflow.com/問題/ 1132941/python-the-mutable-default-argument中的令人驚訝的事情) – 2013-07-12 00:06:22

回答

6

是的;默認參數僅在函數定義時進行評估。

一個可能的解決辦法是有參數是類,而不是一個實例,一拉

def foo(blah, klass = B): 
    b = klass() 
    # etc 
+0

簡而言之,你不能使用可變對象作爲默認值。 – 2009-10-18 20:02:36

+0

當然可以。類在Python中是可變的。它與可變/不可變無關。 – 2009-10-18 20:13:18

+0

使用可變對象會導致此問題中的確切混淆。當你使用一個類作爲默認時,你幾乎總是實例化來創建一個對象。這個類的可變性並不重要,因爲你不是直接使用類,而是使用列表或字典。 – 2009-10-18 22:09:33

15

,你需要做到以下幾點:

class A: 
    def __init__(self, builds=None): 
     if builds is None: 
      builds = B() 
     self.builds = builds 

這是一個非常廣泛的 - 擴展錯誤,使用可變參數作爲默認參數。可能有很多愚蠢的東西。

+1

讓我們找到一個dup並關閉這個? – 2009-10-18 16:22:27

+2

問題是這樣的:你不能使用可變對象作爲默認值。以前的重複都嘗試使用列表。這是第一次使用對象。這是試圖將可變對象用作默認值的「標準問題」。 – 2009-10-18 20:02:02

46

您需要了解的默認值,以便有效地使用它們是如何工作的。

功能是對象。因此,它們具有屬性。所以,如果我創建這個功能:

>>> def f(x, y=[]): 
     y.append(x) 
     return y 

我已經創建了一個對象。這裏是它的屬性:

>>> dir(f) 
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', 
'__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__',  
'__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 
'func_name'] 

其中之一是func_defaults。聽起來很有希望,那裏有什麼?這是一個包含函數默認值的元組。如果默認值是一個對象,則該元組包含該對象的一個​​實例。

這會導致一些非常違反直覺的行爲,如果你認爲f增加了一個項目列表,返回只包含項目的列表,如果沒有提供列表:

>>> f(1) 
[1] 
>>> f(2) 
[1, 2] 

但是,如果你知道默認值是一個儲存在該函數的屬性之一的對象實例,它更是違反直覺:

>>> x = f(3) 
>>> y = f(4) 
>>> x == y 
True 
>>> x 
[1, 2, 3, 4] 
>>> x.append(5) 
>>> f(6) 
[1, 2, 3, 4, 5, 6] 

認識到這一點,很明顯,如果你想要一個函數的參數的默認值是一個新的列表(或任何新的ob ject),你不能簡單地在func_defaults中存儲對象的一個​​實例。每次調用函數時都必須創建一個新的函數:

>>>def g(x, y=None): 
     if y==None: 
      y = [] 
     y.append(x) 
     return y