如何透過引用傳遞變數?

PHPz
發布: 2024-02-09 20:00:05
轉載
554 人瀏覽過

如何透過引用傳遞變數?

問題內容

我寫這個類別是為了測試:

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 這樣的程式碼卻會影響呼叫者的參數。發生這種情況是因為儘管有= 語法,但項目分配切片分配變異現有物件的方法,而不是重新分配變數。請參閱為什麼函數可以修改呼叫者感知到的某些參數,但不能修改其他參數?了解詳情。

另請參閱按引用傳遞與按值傳遞之間有什麼區別?用於重要的、與語言無關的術語討論。


正確答案


參數是透過賦值傳遞。這背後的理由有兩個:

  1. 傳入的參數實際上是物件的引用(但引用是按值傳遞的)
  2. 某些資料型別是可變的,但其他資料型別則不然

所以:

  • 如果將一個可變物件傳遞給方法,則該方法將獲得對相同物件的引用,並且您可以隨心所欲地改變它,但是如果您在方法時,外部作用域對此一無所知,完成後,外部引用仍將指向原始物件。

  • 如果將不可變物件傳遞給方法,您仍然無法重新綁定外部引用,甚至無法變更該物件。

為了更清楚地說明這一點,讓我們舉一些例子。

清單 - 可變類型

讓我們試著修改傳遞給方法的清單:

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_listouter_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_stringouter_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中文網其他相關文章!

相關標籤:
來源:stackoverflow.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!