為了更好的認識函數,我們還要研究值傳遞問題,再研究這個問題之前,我們已經知道了函數之間的值傳遞,是實參變數值傳遞給形參變數,然後讓形參變數在函數內完成相應的功能。但是因為數據類型的不同,這裡的值傳遞產生的對實參變數的效果是不同的 # 1.傳遞數據本質 參數傳遞之間傳遞的肯定是數據,而這種數據本質上是 ...
為了更好的認識函數,我們還要研究值傳遞問題,再研究這個問題之前,我們已經知道了函數之間的值傳遞,是實參變數值傳遞給形參變數,然後讓形參變數在函數內完成相應的功能。但是因為數據類型的不同,這裡的值傳遞產生的對實參變數的效果是不同的
1.傳遞數據本質
參數傳遞之間傳遞的肯定是數據,而這種數據本質上是地址值。變數有四個要素:名、值、數據類型、地址值。每個變數在創建時都會在記憶體中開闢一定空間,該空間具有地址值,併在該地址裡面存儲數據,Python的變數存儲的數據是地址值,該地址值所代表的是真實數據的地址值,而不是變數的地址值。
1.1不可變數據類型
我們之前介紹過數字、字元串、元組它是不可變的,就是說只要在記憶體中創建了該數據,那麼它是不變的,創建了數字1,那麼數字1是存在的,我們把變數進行運算操作,假設進行加法運算,讓其加1,變為了2,那麼這裡是創建了一個數字2,數字2也是不可變的,原先的數字1還是存在的,只不過我們的變數中儲存的數據是數字2的地址值了。
圖中的0x-xx是地址假想值。
id函數在作用於變數時,其返回的是變數指向數據內容的地址值,編寫程式如下所示:
參數之間數據的傳遞,就是將實參變數的值賦值給形參變數,這裡我們說的實參變數的值就是實參數據的地址值,編寫程式如下所示:
我們通過輸出結果發現,num1、num2、num3所存儲的地址值都是相同的,都為140716513424168,這說明他們都指向同一個數據,也就是數字1,但是經過運算後,num3所存儲的地址值變化了,是因為產生了新數據,新數據的地址賦值給了num3,num3指向了數字2的地址
那麼,經過sum函數後,因為num1、num2的地址是沒有發生改變的,所以我們輸出num1和num2它的結果還是1。
這裡我們是用數字舉例的,換成字元串、元組等都是同樣的道理
1.2可變數據類型
不可變數據類型在記憶體中的表現:當不可變數據類型(數字、字元串、元組)的變數需要更新新值時,其創建一個新值,將舊值的地址更換為新值的地址,此時指向發生改變。
可變數據類型,我們目前瞭解的就是列表、字典,我們可以發現它們都不是一個簡單的數據,而是一組相對複雜的數據集合,數據集合裡面包含的數據類型是任意的,就相當於一個倉庫,可變數據類型變數的數據值是倉庫的地址,而我們所說的可變數據類型變數裡面的數據更新新值時,不是倉庫地址的改變,而是倉庫內數據元素的改變。
所以,可變數據類型在記憶體中的表現:當可變數據類型(列表、字典)變數需要更新數據元素新值時,其創建一個數據元素新值,將新值的地址放進可變數據類型所指向的倉庫裡面,而不是改變可變數據類型變數存儲的倉庫的地址值,其邏輯如下圖所示。
圖中的0x-xx是地址假想值。
我們可以做下驗證,編寫程式如下所示:
通過輸出結果我們發現,
1.在經過del_first函數之前,輸出列表數據元素為[1,2,3,4]。在經過del_first函數之後,輸出列表數據元素為[2,3,4]這說明改變了實參變數list所指向的地址中的內容,形象化理解,就是改變了倉庫裡面的內容。
2.在經過del_first函數之前,list變數所存儲的地址值為2113656214912。經過del_first函數之後,list變數所存儲的地址值仍為2113656214912。所以說明list變數經過函數操作後,沒有改變其存儲的地址值,形象化理解,就是沒有改變倉庫的地址
3.在經過del_first函數之前,列表數據元素0所存儲的地址為140712759325480,列表數據元素1所存儲的地址為140712759325512。在經過del_first函數之後,列表數據0所存儲的地址為原先列表數據元素1存儲的地址140712759325512,也就是經過刪除第一個數據元素的操作後,所有數據元素都依次往前排列。形象化理解,就是把倉庫中第一個位置的物品拿出來,然後把其他的物品依次往前挪一個位置。
這裡我們是用列表舉例的,換成字典等其他可變數據類型都是同樣的道理
1.3總結
不可變數據類型的實參變數,經過函數操作之後,不會改變其原有內容
可變數據類型的實參變數,經過函數操作之後,會改變其原有內容