Python-引數傳遞(值/引用傳遞)
【正文部分】
值傳遞(passl-by-value)過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在堆疊中開闢了記憶體空間來存放由主調函式放進來的實參的值,從而想成為了實參的一個副本。值傳遞的特點是被調函式對形式引數的任何操作都是作為區域性變數進行,不會影響主調函式的實參變數的值。【就給你一個值,你自己做個副本就好】
引用傳遞(pass-by-reference)過程中,被調函式的形式引數雖然也作為區域性變數在堆疊中開闢了記憶體空間,但這時存放的是由主調函式放進來的實參變數的地址。被調函式對形參的任何操作都被處理成間接定址,即通過堆疊中存放的地址訪問主調函式中的實參變數。正因為如此,被調函式對形參做任何的操作都影響了主調函式中的實參變數。【給你一份我的地址,可以根據這個隨時找我,你還能在我家吃個飯啥的
名詞解釋:
1、變數與物件
Python 中一切皆為物件,數字是物件,列表是物件,函式也是物件,任何東西都是物件。而變數只是物件的一個引用,物件的操作都是通過引用來完成的。而資料型別是針對【物件】而言的,不是針對【變數】。
2、引用:
可以理解為對物件的記憶體地址指向。
3、賦值
賦值操作的本質就是繫結一個新的物件。
對於不可變資料型別,相當於綁定了一個新的物件,所以進行到是值傳遞的形式,賦值操作完成之後變數引用的物件發生了變化。args=2執行之前,arg拿到了實參變數a的值,成為一個副本物件,對arg進行賦值操作的時候,都是隻作為區域性變數進行,不會對主函式的實參變數a造成影響。
def foo(arg): arg = 2 print(arg) a = 1 foo(a) # 輸出:2 print(a) # 輸出:1
而對於可變資料型別,具有增刪改查的特性,進行增刪改查的時候並沒有賦值操作,所以沒有繫結新的物件,對同一個引用或稱為同一個物件進行增刪改查之後,變數指向的還是該物件。所以進行的是引用傳遞的形式。arg在執行append之前,實參變數b把自己引用物件的地址也給了arg,所以對arg進行操作的時候對引用物件b也進行了修改。
def bar(args): args.append(1) b = [] print(b)# 輸出:[] print(id(b)) # 輸出:4324106952 bar(b) print(b) # 輸出:[1] print(id(b)) # 輸出:4324106952
結論:
python不允許程式設計師選擇採用傳值還是傳引用。python引數傳遞採用的肯定是“傳物件引用”的方式。這種方式相當於傳值和傳引用的一種綜合。
如果函式收到的是一個不可變物件(數字、字元或元組)的引用,就不能直接修改原始物件--相當於通過‘值傳遞’來傳遞物件。
如果函式收到的是一個可變物件(字典、列表)的引用,就能修改物件的原始值--相當於‘傳引用’來傳遞物件。