Python基礎(chǔ)之值傳遞和引用傳遞詳解
在python
中,向函數(shù)傳遞參數(shù)的類型有兩種,一種是值傳遞,還有一種是引用傳遞,如果你恰恰好會一點c
基礎(chǔ),你可以理解為前者為傳遞形參,而后者傳遞指針。本篇文章將探究python
的值傳遞和引用傳遞。
文本所依賴的python
環(huán)境為:
什么是值傳遞和引用傳遞
值傳遞,我們可以理解為傳遞了一個副本過去,即變量的拷貝,修改副本值不會影響原先的值,例如:
def modify_x(x): x = 99 print("函數(shù)中修改過后的值: " , x) x=66 modify_x(x) print("執(zhí)行modify_x函數(shù)后的值:" , x)
在上述代碼中,我們定義了一個變量x
,并賦值為66
,而后將x
傳入其modify_x
函數(shù)中,在函數(shù)中,我們將x
賦值為99
,打印一下函數(shù)中的x
值,函數(shù)結(jié)果。 在主函數(shù)中再打印一下x
的值。
此結(jié)果執(zhí)行后如下:
如上代碼,我們傳入的是形參,在函數(shù)中修改形參是不會改變原先的值的,這是因為函數(shù)運行時候會先進(jìn)行壓棧,運行過程中會產(chǎn)線局部信息等,恰恰好,我們傳入的形參就是該類型的值,所以運行后會出棧,出棧后函數(shù)所在的內(nèi)存也會被銷毀,所以函數(shù)內(nèi)的局部變量隨著出棧也被銷毀了。所以直接修改形參無效。
以上這個就是值傳遞。
那什么是引用傳遞呢?我們還是拿上面這個例子做比方,只不過傳遞的類型換一下,從數(shù)值類型更換為字典類型,如:
def modify_x(dict): dict["x"] = 99 print("數(shù)中修改過后的值:" , dict) a={ "x":66 } modify_x(a) print("執(zhí)行modify_x函數(shù)后的值:", a)
如上代碼,我們定義了一個字典a
,該字典有一個key
為x
,值為66
。在調(diào)用modify_x
函數(shù)中,我們將a
傳遞給了函數(shù),在函數(shù)中,我們將該字典key
為x
的賦值為99
,函數(shù)結(jié)束,在主函數(shù)中打印a
的值。
執(zhí)行后結(jié)果如下:
是不是感覺很詫異,同樣的代碼,為什么傳遞整形 和 傳遞 字典 , 所執(zhí)行的效果不一樣呢? 這是因為python
機(jī)制就是如此,它在傳遞該值的時候,使用的是指針傳遞,所以值沒有改變,我們將其稱之為引用傳遞。
可以干預(yù)參數(shù)傳遞是值傳遞還是引用傳遞么
python
不可以干預(yù)參數(shù)傳遞的類型,因為python
不像c
、c++
一樣,可以傳遞形參,也可以傳遞指針類型。
在python
中,參數(shù)傳遞是由解釋器實現(xiàn)的,所以說,普通開發(fā)者,沒辦法直接干預(yù)參數(shù)傳遞方式,但是可以曲線救國,善用return
就是其中一條,例如我們將最開始的代碼修改一下,不直接修改值,而是返回一個新的值,例如:
def modify_x(x): x = 99 return x x = 66 x = modify_x(x) print("執(zhí)行modify_x函數(shù)后的值:" , x)
我們執(zhí)行后,結(jié)果為:
這并不是修改x
的值,而是接收modify_x
傳遞回來的新值。
探尋一下值傳遞底層是如何實現(xiàn)的
我們之前所述的值傳遞,都是對數(shù)據(jù)的拷貝,可是現(xiàn)實真的如此么? 我們可以寫一個案例來看下:
def modify_x(x): print("函數(shù)中:",id(x)) x = 123 print("函數(shù)外:",id(x)) modify_x(x)
在上述代碼中,有一個新的知識點是方法id
,它可以查看變量的內(nèi)存地址。在上述例子中,在主函數(shù)中定義一個整形x
,值為123
,在傳遞給函數(shù)前,使用id
方法查看一下變量的內(nèi)存地址。而后傳遞給函數(shù)modify_x
,在該函數(shù)中,也使用id
方法來查看一下形參x
的地址。
若真如我們所猜想,那么2個內(nèi)存地址應(yīng)該不一致才對,我們運行下程序:
發(fā)現(xiàn)函數(shù)內(nèi),和函數(shù)外的地址都是一樣的? 哎,這是怎么回事呢?
這是因為在python
中,解釋器為了優(yōu)化性能,避免大量無用數(shù)據(jù)拷貝,所以在傳遞的時候,一開始全是傳遞的實參,只有當(dāng)函數(shù)內(nèi)修改了值后,才會新申請一個內(nèi)存來存該值。細(xì)節(jié)可以查看這個例子:
def modify_x(x) : print("函數(shù)中1:",id(x)) x = 456 print("函數(shù)中2:",id(x)) x=123 print("函數(shù)外0:",id(x)) modify_x(x)
上述代碼,我們在modify_x
函數(shù)中,修改變量x
前后都打印其內(nèi)存地址,結(jié)果如下:
我們發(fā)現(xiàn),在未修改之前,地址內(nèi)存都是指向同一個地址,修改之后,內(nèi)存地址也變了。
如果我們將x
更換為引用傳遞的數(shù)據(jù)的話,就不會出現(xiàn)以下這種情況,可以看下面這個例子:
def modify x(x) : print("函數(shù)中1:",id(x)) x[0] = 456 print("函數(shù)中2:",id(x)) x = [123] print("函數(shù)外0:",id(x)) modify_x(x) print("最后的值:" , x)
上述代碼,我們做了一個小小的改動,我們將整形數(shù)據(jù)x
,更改為了列表類型,最后再打印一下x
的值,查看變了沒有,代碼運行結(jié)果如下:
發(fā)現(xiàn)內(nèi)存地址的值并沒有改變,且x
的值在函數(shù)中真的被修改了。
所以通過上述例子,可以說明,值傳遞的時候,再沒有修改的時候,該變量地址還是指向原來的地址,當(dāng)值被修改后,就會開辟一個新的內(nèi)存地址用于存儲該值。這樣的話可以避免拷貝大量數(shù)據(jù)。
最后再總結(jié)一下,哪些類型是引用傳遞,哪些類型是值傳遞:
引用傳遞分別有 列表、字典、集合、自定義類實例等。
值傳遞分別有 字符串類型、元組、布爾類型、數(shù)值類型等。
總結(jié)
本篇文章簡單介紹了值傳遞和引用傳遞,值傳遞,修改函數(shù)內(nèi)值后,不會影響原始值,而引用傳遞,修改函數(shù)內(nèi)值后,會印象到原始數(shù)據(jù)。不過有一個小細(xì)節(jié),就是值傳遞,若不進(jìn)行修改值的時候,其實內(nèi)存地址是指向的原始值的地址,當(dāng)修改值的時候,才會真正申請內(nèi)存來存儲修改的值,但是隨著函數(shù)出棧,該函數(shù)內(nèi)的數(shù)據(jù)局部變量,也會被銷毀。
到此這篇關(guān)于Python基礎(chǔ)之值傳遞和引用傳遞詳解的文章就介紹到這了,更多相關(guān)Python值傳遞 引用傳遞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入探究PyTorch核心特性之自動求導(dǎo)和優(yōu)化
在你已經(jīng)掌握了如何使用PyTorch構(gòu)建神經(jīng)網(wǎng)絡(luò)的基礎(chǔ)上,接下來我們將深入探討PyTorch的兩個核心特性:自動求導(dǎo)(Autograd)和優(yōu)化(Optimization),這兩個特性在深度學(xué)習(xí)模型的訓(xùn)練過程中起著至關(guān)重要的作用,感興趣的同學(xué)一起來看看吧2023-07-07python基礎(chǔ)學(xué)習(xí)之遞歸函數(shù)知識總結(jié)
在函數(shù)中調(diào)用函數(shù)自身,我們把這樣的函數(shù)叫做遞歸函數(shù), 遞歸函數(shù)就是循環(huán)的調(diào)用,類似于俄羅斯套娃,本文給各位小伙伴詳細(xì)介紹了python遞歸函數(shù),需要的朋友可以參考下2021-05-05pycharm2020上部署配置AutoGPT4.0(保姆級教程)
本文主要介紹了pycharm2020上部署配置AutoGPT4.0,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06Python+Matplotlib實現(xiàn)繪制三維折線圖
立體圖視覺上層次分明色彩鮮艷,具有很強(qiáng)的視覺沖擊力,讓觀看的人駐景時間長,留下深刻的印象。今天我們就通過這篇文章來了解如何用python中的matplotlib庫繪制漂亮的三維折線圖吧2023-03-03