Python文檔彷佛尚不清楚參數是經過引用仍是經過值傳遞,而且如下代碼產生不變的值「原始」 html
class PassByReference: def __init__(self): self.variable = 'Original' self.change(self.variable) print(self.variable) def change(self, var): var = 'Changed'
我能夠作些什麼來經過實際引用傳遞變量嗎? python
從技術上講, Python始終使用按引用傳遞值 。 我將重複其餘答案以支持個人發言。 數據庫
Python始終使用按引用傳遞值。 也不例外。 任何變量分配都意味着複製參考值。 沒有例外。 任何變量都是綁定到參考值的名稱。 老是。 編程
您能夠將參考值視爲目標對象的地址。 該地址在使用時會自動取消引用。 這樣,使用參考值,彷佛您能夠直接使用目標對象。 可是,二者之間老是存在一個參考,距離目標還有一步之遙。 app
這是證實Python使用引用傳遞的示例: 編程語言
若是參數經過值傳遞,則外部lst
沒法修改。 綠色是目標對象(黑色是內部存儲的值,紅色是對象類型),黃色是內部具備參考值的存儲器-繪製爲箭頭。 藍色實心箭頭是傳遞給函數的參考值(經過虛線藍色箭頭路徑)。 醜陋的深黃色是內部詞典。 (實際上也能夠將其繪製爲綠色橢圓形。顏色和形狀僅表示它是內部的。) 函數
您可使用id()
內置函數來了解參考值是什麼(即目標對象的地址)。 spa
在編譯語言中,變量是可以捕獲類型值的內存空間。 在Python中,變量是綁定到引用變量的名稱(在內部以字符串形式捕獲),該變量將引用值保存到目標對象。 變量的名稱是內部字典中的鍵,該字典項的值部分將參考值存儲到目標。 指針
參考值隱藏在Python中。 沒有用於存儲參考值的任何明確的用戶類型。 可是,您能夠將list元素(或任何其餘合適的容器類型的元素)用做參考變量,由於全部容器的確會將這些元素存儲爲對目標對象的引用。 換句話說,元素實際上不包含在容器內,僅包含對元素的引用。 code
這是Python中使用的pass by object
概念的簡單解釋(我但願如此)。
每當將對象傳遞給函數時,都會傳遞對象自己(Python中的對象其實是您在其餘編程語言中稱爲值的對象),而不是對該對象的引用。 換句話說,當您致電時:
def change_me(list): list = [1, 2, 3] my_list = [0, 1] change_me(my_list)
正在傳遞實際對象-[0,1](在其餘編程語言中將其稱爲值)。 所以,實際上,函數change_me
將嘗試執行如下操做:
[0, 1] = [1, 2, 3]
這顯然不會改變傳遞給函數的對象。 若是函數看起來像這樣:
def change_me(list): list.append(2)
而後,該調用將致使:
[0, 1].append(2)
這顯然會改變對象。 這個答案很好地解釋了。
Effbot(又名Fredrik Lundh)將Python的變量傳遞樣式描述爲按對象調用: http : //effbot.org/zone/call-by-object.htm
對象在堆上分配,指向它們的指針能夠在任何地方傳遞。
當您進行x = 1000
類的賦值時,將建立一個字典條目,該條目將當前名稱空間中的字符串「 x」映射到一個指向包含1000的整數對象的指針。
當使用x = 2000
更新「 x」時,將建立一個新的整數對象,而且字典將更新爲指向該新對象。 舊的一千個對象保持不變(取決於其餘是否引用了該對象,該對象是否能夠存活)。
當您進行新的賦值(例如y = x
,將建立一個新的字典條目「 y」,該條目指向與「 x」條目相同的對象。
諸如字符串和整數之類的對象是不可變的 。 這僅表示沒有任何方法能夠在建立對象後更改該對象。 例如,一旦建立了整數對象1000,它就永遠不會改變。 數學是經過建立新的整數對象完成的。
像列表這樣的對象是可變的 。 這意味着能夠經過指向該對象的任何內容來更改該對象的內容。 例如, x = []; y = x; x.append(10); print y
x = []; y = x; x.append(10); print y
x = []; y = x; x.append(10); print y
將打印[10]
。 空列表已建立。 「 x」和「 y」都指向同一列表。 append方法會更改(更新)列表對象(例如向數據庫中添加記錄),而且結果對於「 x」和「 y」都是可見的(就像數據庫更新對於該數據庫的每一個鏈接都是可見的同樣)。
但願能爲您解決問題。
如您所言,您須要有一個可變的對象,可是讓我建議您檢查一下全局變量,由於它們能夠幫助您甚至解決此類問題!
例:
>>> def x(y): ... global z ... z = y ... >>> x <function x at 0x00000000020E1730> >>> y Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'y' is not defined >>> z Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'z' is not defined >>> x(2) >>> x <function x at 0x00000000020E1730> >>> y Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'y' is not defined >>> z 2
理解參數傳遞的關鍵是中止考慮「變量」。 Python中有名稱和對象,它們一塊兒看起來像變量,可是始終區分這三個名稱頗有用。
這就是所有。 可變性與這個問題無關。
例:
a = 1
這會將名稱a
綁定到具備值1的整數類型的對象。
b = x
這會將名稱b
綁定到名稱x
當前綁定到的同一對象。 此後,名稱b
與名稱x
無關。
在問題所示的代碼中,語句self.Change(self.variable)
將名稱var
(在Change
函數的範圍內self.Change(self.variable)
綁定到持有值'Original'
和賦值var = 'Changed'
(在函數體Change
)再次爲該對象分配了相同的名稱:另外一個對象(碰巧也包含一個字符串,但可能徹底是其餘東西)。
(編輯2019-04-28)
所以,若是要更改的對象是可變對象,則沒有問題,由於全部內容均經過引用有效地傳遞。
若是它是一個不可變的對象(例如布爾,數字,字符串),則將其包裝在一個可變的對象中。
對此的快速解決方案是一個元素列表(而不是self.variable
,傳遞[self.variable]
並在函數中修改var[0]
)。
更加Python化的方法是引入一個瑣碎的,一屬性類。 該函數接收該類的實例並操縱該屬性。