2012-12-26 126 views
4

我有一個函數,我使用局部變量,然後在函數完成後返回最終變量。我想保留這個變量在函數前的記錄,但全局變量和局部變量一起更新。下面是我的代碼的縮寫版本(其相當長)Python:局部變量神祕地更新全局變量

def Turn(P,Llocal,T,oflag): 
    #The function here changes P, Llocal and T then passes those values back 
    return(P, Llocal, T, oflag) 

#Later I call the function 
#P and L are defined here, then I copy them to other variables to save 
#the initial values 

P=Pinitial 
L=Linitial 
P,L,T,oflag = Turn(P,L,T,oflag) 

我的問題是,L和Linitial都更新,什麼時候Llocal被更新,但我想Linitial不改變。 P不會改變,所以我對這裏發生的事情感到困惑。幫幫我?謝謝!

爲勇敢的人,整個代碼是在這裏:https://docs.google.com/document/d/1e6VJnZgVqlYGgYb6X0cCIF-7-npShM7RXL9nXd_pT-o/edit

+2

什麼類型的對象?你能給出一個完整的,自包含的可運行的例子來證明你看到了什麼嗎? –

+0

P是一個整數,L是一個列表。 T也是一個整數,oflag是一個布爾值。我只通過IDLE的調試器發現了這個問題,它非常微妙。如果我顯示全局變量和局部變量,我會看到L,Linitial和Llocal全部三個同時變化。我可以在這裏上傳整個代碼,但是它有幾百行。我現在擔心的部分現在開始於190和57左右。目前它從第66行引發錯誤,但錯誤的根源是此變量更新。 – mykinz

+0

請注意[PEP-8](http://www.python.org/dev/peps/pep-0008/)建議爲類名保留'CapWords'。 –

回答

1

列表是可變的。如果您將一個列表傳遞給一個函數,並且該函數修改了該列表,那麼您將能夠看到綁定到同一個列表的任何其他名稱的修改。

要解決該問題,嘗試修改此行:

L = Linitial 

這樣:

L = Linitial[:] 

這片使得列表的淺表副本。如果您添加或刪除存儲在L列表中的項目,它將不會更改列表Lintial

如果要製作深度複製,請使用copy.deepcopy


P也不會發生同樣的情況,因爲它是一個整數。整數是不變的。

+0

我試過使用copy.deepcopy和L = Linitial [:]但我仍然像以前一樣得到相同的錯誤。我正在通過調試器完成它,當我看到發生了什麼時,我會回覆。謝謝! – mykinz

+0

它現在可以工作!實際上我不得不兩次做一個淺拷貝,當我定義Linitial和當我重新定義L.謝謝! – mykinz

2

的問題是,P和L是namesboundobjects,不重視自己。當你將它們作爲參數傳遞給一個函數時,實際上是將一個綁定的副本傳遞給P和L.這意味着,如果P和L是可變對象,對它們所做的任何更改都將在函數調用之外可見。

您可以使用copy模塊保存名稱值的副本。

+0

作爲一個說明,'copy'是一個模塊,而不是一個函數。 –

+0

我認爲這種情況下,函數接收到一個指針並在同一個對象上運行的初始值就足夠了。然而,不可變對象通常在賦值時被複制隱含(例如數字和字符串),而可變對象將同一個指針分配給新名稱,因此您有兩個引用同一實例的名稱。 –

+0

@ Nisan.H Python語言沒有「指針」的概念,所以這沒有用(儘管cPython,實現,使用指針)。而不可變對象不是「在賦值時複製」的。這個名字只是重新綁定到分配給的任何東西。 – jknupp

0

在Python中,變量只是對內存中對象或值的引用。例如,當你有一個清單x

x = [1, 2, 3] 

所以,當你將x另一個變量,我們稱之爲y,你只是創建一個新的參考(y)由x引用的對象( [1, 2, 3]列表)。

y = x 

當您更新x,你實際上是在更新由x所指向的對象,即列表[1, 2, 3]。由於y引用相同的值,它似乎也被更新。

請記住,變量只是對象的引用。

如果你真的想複製一個列表,你務必做好:

new_list = old_list[:] 

這裏有一個很好的解釋:http://henry.precheur.org/python/copy_list