list修改元素的值_第115天:Python 到底是值传递还是引用传递
我們平時(shí)寫的 Python 程序中充斥著大量的函數(shù),包括系統(tǒng)自帶函數(shù)和自定義函數(shù),當(dāng)我們調(diào)用函數(shù)時(shí)直接將參數(shù)傳遞進(jìn)去然后坐等接收返回值即可,簡(jiǎn)直不要太好用。那么你知道函數(shù)的參數(shù)是怎么傳遞的么,是值傳遞還是引用傳遞呢,什么又是值傳遞和引用傳遞呢?
這個(gè)問題對(duì)于很多初學(xué)者還是比較有難度的,看到這里你可以稍加停頓,自己思考一下,看看自己是否真正理解了。很多人只是知道概念但是讓他說他又說不清楚,思考過后如果你還覺得模糊的話,往下仔細(xì)看,我今天就帶著你深入剖析下函數(shù)的參數(shù)傳遞機(jī)制。
為了搞清楚函數(shù)的參數(shù)傳遞機(jī)制,你必須先徹底理解形參和實(shí)參。例如下面的 sayHello 函數(shù),括號(hào)里面的 name 就是形參,而當(dāng)調(diào)用函數(shù)時(shí)傳遞的 name 是實(shí)參。
def sayHello(name): # name 是形式參數(shù) print("Hello %s" % name)name = "hanmeimei" # name 是實(shí)際參數(shù)sayHello(name)# 輸出結(jié)果Hello hanmeimei值傳遞 OR 引用傳遞
上面我們說了,當(dāng)調(diào)用函數(shù)時(shí)我們會(huì)把實(shí)際參數(shù)傳遞給形式參數(shù)。而這個(gè)傳遞過程有兩種,就是我們上文說的值傳遞和引用傳遞了。
顧名思義,所謂值傳遞就是指在傳遞過程中將實(shí)際參數(shù)的值復(fù)制一份傳遞給形式參數(shù),這樣即使在函數(shù)執(zhí)行過程中對(duì)形式參數(shù)進(jìn)行了修改,形式參數(shù)也不會(huì)有所改變,因?yàn)槎呋ゲ桓蓴_。而引用傳遞是值將實(shí)際參數(shù)的引用傳遞給實(shí)際參數(shù),這樣二者就會(huì)指向同一塊內(nèi)存地址,在函數(shù)執(zhí)行過程中對(duì)形式參數(shù)進(jìn)行了修改,形式參數(shù)也會(huì)一并=被修改。
為了故事的順利發(fā)展,我們先來看看 Python 中關(guān)于變量的賦值。
>>> a = 10>>> b = a>>> a = a + 10>>> a20>>> b10>>>在上述的例子中,我們聲明了一個(gè)變量 a,其值為 10,然后將 b 也指向 a,這是在內(nèi)存中的布局是這樣的,變量 a 和 b 會(huì)指向同一個(gè)對(duì)象 10,而不是給 b 重新生成一個(gè)新的對(duì)象。
由此可知,同一個(gè)對(duì)象是可以被多個(gè)對(duì)象引用的。
當(dāng)執(zhí)行完 a = a + 10 后,因?yàn)檎麛?shù)是不可變對(duì)象,所以并不會(huì)將 10 變成 20,而是生成一個(gè)新的對(duì)象 20 ,然后 a 會(huì)指向這個(gè)新的對(duì)象。b 還是指向舊對(duì)象 10。
所以,最后就是 a 為 20,而 b 為 10。
理解了上面的賦值過程之后,我們?cè)賮砜纯磪?shù)的傳遞。老規(guī)矩,還是直接看例子吧,代碼是不會(huì)騙人的。
def swap(a, b): a, b = b, a print("in swap a = %d and b = %d " % (a, b))a = 100b = 200swap(a, b)print("in main a = %d and b = %d " % (a, b))## 輸出結(jié)果in swap a = 200 and b = 100 in main a = 100 and b = 200我們?cè)诤瘮?shù) swap 中交換 a 和 b 的值,然后分別在主函數(shù)和 swap 函數(shù)中輸出其結(jié)果,由結(jié)果可知,swap 函數(shù)并不會(huì)改變實(shí)際參數(shù) a,b 的值,因此我們可以得出結(jié)論,Python 函數(shù)參數(shù)是按照值傳遞的。
別急,不妨再看多一個(gè)例子。
def swap(list): list.append(4) print("in swap list is %s " % list)list_x = [1, 2, 3]swap(list_x)print("in main list is %s " % list_x)## 輸出結(jié)果in swap list is [1, 2, 3, 4] in main list is [1, 2, 3, 4]咦,值被改了,這不就是引用傳遞了么。于是,我們又得出結(jié)論,Python 函數(shù)參數(shù)是按照引用傳遞的。
這未免有點(diǎn)太不嚴(yán)謹(jǐn)了,事實(shí)上我們上面的第二個(gè)例子有點(diǎn)不太嚴(yán)謹(jǐn),我稍微修改了下 swap 函數(shù),咱們?cè)诳纯礈y(cè)試結(jié)果。
def swap(list): list = list + [4] print("in swap list is %s " % list)## 輸出結(jié)果in swap list is [1, 2, 3, 4] in main list is [1, 2, 3]我們只是更改了 swap 函數(shù)內(nèi)一行代碼,結(jié)果就完全不一樣了。為了更好的理解其執(zhí)行過程,我畫了張圖。
在第一個(gè)關(guān)于 list 的例子中,我們首先聲明了一個(gè)列表,其中的元素為 [1,2,3],此時(shí)其內(nèi)存布局如上圖中的步驟一所示。list_x 指向內(nèi)存地址為 OX7686934F 的區(qū)域。
當(dāng)調(diào)用 swap 函數(shù)將 list_x 傳遞給形式參數(shù) list 時(shí),會(huì)將該地址直接傳遞過去,list 也會(huì)指向這個(gè)地址,如步驟二所示。
最后,由于列表是可變的,所以當(dāng) list 在向列表中添加元素時(shí),list_x 自然會(huì)受到影響,因?yàn)槎咧赶虻氖峭粔K內(nèi)存。
所以,這里也是值傳遞,只不過傳遞的值是對(duì)象的內(nèi)存地址罷了。
第二個(gè)關(guān)于 list 的例子中,我們對(duì) swap 函數(shù)進(jìn)行了修改,其執(zhí)行流程如下圖所示。
在執(zhí)行 swap 函數(shù)之前都與上面的例子毫無差別。在 swap 函數(shù)內(nèi)部 list = list + [4] 表示新建一個(gè)末尾加入元素 4 的新的列表,并讓 list 指向這個(gè)新的內(nèi)存地址 ?OX7686936A。因?yàn)槭巧闪艘粋€(gè)新的對(duì)象,與原對(duì)象無關(guān),所以 list_x 不受影響。
簡(jiǎn)而言之,弄清楚改變變量和重新賦值的區(qū)別就好了,第一個(gè)例子中我們改變了變量的值,所以當(dāng)函數(shù)執(zhí)行結(jié)束后所有指向該對(duì)象的變量都會(huì)受影響。而重新賦值相當(dāng)于重新生成一個(gè)新的對(duì)象并在新的對(duì)象上做操作,因此舊對(duì)象不受影響。
如果我們要想在函數(shù)中改變對(duì)象,第一可以傳入可變數(shù)據(jù)類型(列表,字典,集合),直接改變;第二還可以創(chuàng)建一個(gè)新的對(duì)象,修改后返回。建議用后者,表達(dá)清晰明了,不易出錯(cuò)。
總結(jié)
本文介紹了 Python 函數(shù)的參數(shù)傳遞機(jī)制。理解了參數(shù)的傳遞過程和底層實(shí)現(xiàn)細(xì)節(jié),寫代碼時(shí)將會(huì)少犯一些不必要的低級(jí)錯(cuò)誤。
最后,無論是值傳遞還是引用傳遞,我們只需關(guān)注函數(shù)內(nèi)部是否會(huì)生成新的對(duì)對(duì)象即可。凡是對(duì)原對(duì)象操作的函數(shù),都會(huì)影響傳遞的實(shí)際參數(shù);凡是生成了新對(duì)象的操作,都不會(huì)影響傳遞的實(shí)際參數(shù)。
代碼地址
示例代碼:https://github.com/JustDoPython/python-100-day/tree/master/day-115
系列文章??第 114 天:三木板模型算法項(xiàng)目實(shí)戰(zhàn)
??第 113 天:Python XGBoost 算法項(xiàng)目實(shí)戰(zhàn)
??第 112 天:機(jī)器學(xué)習(xí)算法之蒙特卡洛
??第 111 天:Python 垃圾回收機(jī)制
從 0 學(xué)習(xí) Python 0 - 110 大合集總結(jié)PS:公號(hào)內(nèi)回復(fù) :Python,即可進(jìn)入Python 新手學(xué)習(xí)交流群,一起100天計(jì)劃!-END-Python 技術(shù)關(guān)于 Python 都在這里總結(jié)
以上是生活随笔為你收集整理的list修改元素的值_第115天:Python 到底是值传递还是引用传递的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中后台管理信息系统通用原型方案_Axur
- 下一篇: 字符文本中的字符太多_文本对抗---字符