2014-12-24 86 views
2

Python初學者的問題。我試圖改變一個函數內部的一些變量的值,我不明白爲什麼有時它有效,有時它不會。所以我想知道幕後發生了什麼。如果我寫:爲什麼我不能在函數中使用kwargs來更改變量?

def assign(self, **kwargs): 

    kwargs['test'] = 3 
    kwargs['steps'] += [1] 

t = 1 
s = [] 

assign(test=t, steps=s) 

print(t) 
print(s) 

這仍然打印

1 
[] 

現在,如果我改變功能分配給

def assign(self, **kwargs): 

    kwargs['test'] += 3 
    kwargs['steps'] += [1, 2, 3] 

它改變了列表,但不是整數。所以我想這與整數是不可變的,列表是可變的這一事實有關。所以我想用字典來確保我的變量被改變了。所以後來:

dict = {'test':1, 'steps': []} 
assign(**dict) 
print(dict) 

仍然打印

{'test': 1, 'steps': [1, 2, 3]} 

具有完全相同的行爲,所以現在我真的很困惑。看來,解壓縮字典時,我不再傳遞對字典變量的引用,以便這些unpacked變量正在被值複製?什麼是最好的方式來實現我想要做的事情呢?

UPDATE

由於與@ 6502的討論,因爲

在Python有沒有辦法改變已經傳遞給函數,因爲你不能有「指針」的參數或「參考」。

最pythonic的方式是不這樣做。一個函數接收參數並提供結果。如果參數是可變的,它可以改變它的狀態,但是改變調用參數本身被認爲是不需要的。

然後,我決定返回的結果,而不是一本字典:

def assign(self, **kwargs): 

    kwargs['test'] += 3 
    kwargs['steps'] += [1, 2, 3] 
    return kwargs 

dict = {'test':1, 'steps': []} 
dict = assign(**dict) 
print(dict) 

這個工作,當然,但我不知道對大數據的影響,因爲它在我看來,(從C來++世界),有很多複製。

+1

簡單地直接傳遞一個字典的功能和接受它作爲一個普通的說法,這是沒有必要的。 – yole

+0

是的,我知道這是有效的,但我不能解壓縮多個字典。我想明白爲什麼這個'kwargs'不起作用。 – aaragon

+2

你可能想看看http://stackoverflow.com/questions/16039280/mutability-of-the-kwargs-argument-in-python – hyades

回答

1

一個簡單的方法,理順語義是要考慮到所有的Python值確實對象的指針,而這些指針總是按值傳遞。

如果您更改指向調用者的對象可以看到突變,但是如果您指定了該變量,那麼您只需更改它指向的內容並且調用者不會注意到。

在Python中,無法更改已傳遞給函數的參數,因爲您不能擁有「指針」或「引用」。變異變量的唯一方法是使用其名稱。

一個變通辦法(在Python 3)是通過可以訪問本地的封閉,例如:

def foo(x, y, set_result): 
    set_result(x + y) 

def bar(): 
    res = None 
    def set_res(x): 
     nonlocal res 
     res = x 
    foo(10, 20, set_res) 
    print(res) 

這種掛羊頭賣狗肉然而很少需要,因爲在語言參考參數傳遞最常見的用途是返回多個值,例如(C++)

bool read_xy(double& x, double& y); 

其中函數需要返回三個值,x,y和成功標誌。

在Python然而,你可以只寫

return x, y 

,並用它作爲

x, y = read_xy() 
+0

因此,如果在Python中沒有辦法改變一個參數已經傳遞給一個函數,因爲你不能有「指針」或「引用」_,那麼模仿這個的最好的Pythonic方法是什麼? – aaragon

+0

@aaragon:最pythonic的方式是不這樣做。一個函數接收參數並提供結果。如果參數是可變的,它可以改變它的狀態,但改變調用參數本身被認爲是不需要的。事實上即使在C++中通過非const引用傳遞一個參數也有一些難聞的氣味......至少如果它是一個輸出參數接受一個顯式指針:這種方式不會發生函數調用者驚訝價值改變。 – 6502

2

第一個例子是錯誤的,你得到s=[1]

這是因爲列表s是一個參數,steps並更改該列表中的內容。 簡單多了:

def assign(step): 
    step += [1] # change the contents of the list 

s = [] 
assign(step=s) 
print(s) # gives [1] 

這是無關的關鍵字參數或字典擴展。如果您使用**或直接給出關鍵詞,因爲參數完全相同。

不要試圖通過參考»傳遞變量。 python是不可能的。改用返回值。

def assign(test, steps): 
    return 3, steps + [1] 

t, s = assign(3, []) 
相關問題