我寫這個類別是為了測試:
class PassByReference: def __init__(self): self.variable = 'Original' self.change(self.variable) print(self.variable) def change(self, var): var = 'Changed'
當我嘗試建立實例時,輸出是 original
。所以python中的參數似乎是按值傳遞的。那是對的嗎?如何修改程式碼才能達到引用傳遞的效果,使得輸出為changed
?
有時人們會感到驚訝,像x = 1
這樣的程式碼(其中x
是參數名稱)不會影響呼叫者的參數,但像 x[0] = 1
這樣的程式碼卻會影響呼叫者的參數。發生這種情況是因為儘管有=
語法,但項目分配和切片分配是變異現有物件的方法,而不是重新分配變數。請參閱為什麼函數可以修改呼叫者感知到的某些參數,但不能修改其他參數?了解詳情。
另請參閱按引用傳遞與按值傳遞之間有什麼區別?用於重要的、與語言無關的術語討論。
參數是透過賦值傳遞。這背後的理由有兩個:
所以:
如果將一個可變物件傳遞給方法,則該方法將獲得對相同物件的引用,並且您可以隨心所欲地改變它,但是如果您在方法時,外部作用域對此一無所知,完成後,外部引用仍將指向原始物件。
如果將不可變物件傳遞給方法,您仍然無法重新綁定外部引用,甚至無法變更該物件。
為了更清楚地說明這一點,讓我們舉一些例子。
讓我們試著修改傳遞給方法的清單:
def try_to_change_list_contents(the_list): print('got', the_list) the_list.append('four') print('changed to', the_list) outer_list = ['one', 'two', 'three'] print('before, outer_list =', outer_list) try_to_change_list_contents(outer_list) print('after, outer_list =', outer_list)
輸出:
before, outer_list = ['one', 'two', 'three'] got ['one', 'two', 'three'] changed to ['one', 'two', 'three', 'four'] after, outer_list = ['one', 'two', 'three', 'four']
由於傳入的參數是對 outer_list
的引用,而不是它的副本,因此我們可以使用變異列表方法來更改它,並將更改反映在外部範圍中。
現在讓我們看看當我們嘗試更改作為參數傳入的參考時會發生什麼:
#def try_to_change_list_reference(the_list): print('got', the_list) the_list = ['and', 'we', 'can', 'not', 'lie'] print('set to', the_list) outer_list = ['we', 'like', 'proper', 'english'] print('before, outer_list =', outer_list) try_to_change_list_reference(outer_list) print('after, outer_list =', outer_list)
輸出:
before, outer_list = ['we', 'like', 'proper', 'english'] got ['we', 'like', 'proper', 'english'] set to ['and', 'we', 'can', 'not', 'lie'] after, outer_list = ['we', 'like', 'proper', 'english']
由於 the_list
參數是按值傳遞的,因此為其指派新清單不會對方法外部的程式碼產生任何影響。 the_list
是 outer_list
引用的副本,我們讓 the_list
指向一個新列表,但無法更改 outer_list
指向的位置。
它是不可變的,因此我們無法更改字串的內容
#現在,讓我們嘗試更改引用
def try_to_change_string_reference(the_string): print('got', the_string) the_string = 'in a kingdom by the sea' print('set to', the_string) outer_string = 'it was many and many a year ago' print('before, outer_string =', outer_string) try_to_change_string_reference(outer_string) print('after, outer_string =', outer_string)
輸出:
before, outer_string = it was many and many a year ago got it was many and many a year ago set to in a kingdom by the sea after, outer_string = it was many and many a year ago
同樣,由於 the_string
參數是按值傳遞的,因此為其指派新字串不會對方法外部的程式碼看到任何影響。 the_string
是 outer_string
引用的副本,我們讓 the_string
指向一個新字串,但無法更改 outer_string
指向的位置。
我希望這能讓事情變得更清楚。
編輯:有人指出,這並沒有回答 @david 最初提出的問題:「我可以做些什麼來透過實際引用傳遞變數嗎?」。讓我們努力吧。
正如@andrea的回答所示,您可以傳回新值。這不會改變傳入內容的方式,但可以讓您獲得想要的資訊:
def return_a_whole_new_string(the_string): new_string = something_to_do_with_the_old_string(the_string) return new_string # then you could call it like my_string = return_a_whole_new_string(my_string)
如果您確實想避免使用返回值,您可以建立一個類別來保存您的值並將其傳遞給函數或使用現有的類,例如列表:
def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change): new_string = something_to_do_with_the_old_string(stuff_to_change[0]) stuff_to_change[0] = new_string # then you could call it like wrapper = [my_string] use_a_wrapper_to_simulate_pass_by_reference(wrapper) do_something_with(wrapper[0])
雖然這看起來有點麻煩。
以上是如何透過引用傳遞變數?的詳細內容。更多資訊請關注PHP中文網其他相關文章!