Python 可變型別和不可變型別及引用過程解析
在Python中定義一個數據便在記憶體中開闢一片空間來儲存這個變數的值,這塊已經被分配的記憶體空間便會有一個記憶體地址。訪問這塊記憶體需要用到變數名,變數名實際儲存的是變數的地址在記憶體中的地址,但是使用print()函式得到的確實這塊記憶體中實際的地址。這個就當成規定就好,沒必要糾結。
獲得變數在記憶體中的地址,可以使用id()函式。
常規使用
變數之間的賦值其實是把一個變數的記憶體地址傳遞給另一個變數,這樣兩個變數便都指向記憶體中的同一塊空間,因此這兩個變數的之是相等的
a = 1 b = a print("a:%d b:%d" % (a,b)) print(id(a)) print(id(b)) 結果: a:1 b:1 1711072016
此時如果有第三個變數c的值與a的相等,那麼c的地址與a的地址一樣。這一點請大家牢記。
a = 1 c = 1 print("a:%d c:%d" % (a,c)) print(id(a)) print(id(c)) 結果: a:1 c:1 1711072016
此時如果修改變數c的值,那麼會在記憶體中新開闢一塊記憶體來儲存這個變數,這塊新的記憶體地址將會賦值給c。
a = 1 c = 1 c = 2 print("a:%d c:%d" % (a,c)) print(id(a)) print(id(c)) 結果: a:1 c:2 1711072032
基本資料型別作為函式引數
基本資料型別作為函式實參同樣是這個道理。
a = 1 print(id(a)) def func(x): print(id(x)) x = 2 print(id(x)) func(a) 結果: 1711072016
列表、字典等高階資料型別的引用
列表字典等高階資料型別的變數名同樣儲存的變數的實際地址,一個列表名賦值給另一個變數,那麼這兩個變數便指向記憶體中的同一塊地址。
list1 = [1,2,3] list2 = list1 print(list1,list2) print(id(list1),id(list2)) 結果: [1,3] [1,3] 57931896
高階資料型別在每集載入進記憶體的時候記憶體地址與上一次可能會不同。
此時如果修改list2,也會影響list1的值,但是兩個變數在記憶體中的地址還是不變的。這一點是與基本資料型別不一樣的。
list1 = [1,id(list2)) list2.append(4) print(list1,id(list2)) 結果: [1,3] 43841656 [1,3,4] [1,4] 43841656
此時如果有第三個列表list3的值也是[1,4],可以推測list3的地址與list1的地址應該是一樣的,但是事實並非如此。如果有第三個列表list3的值也是[1,相當於在記憶體中新開闢一塊記憶體來儲存這個值。
list1 = [1,3] list2 = list1 list3 = [1,3] print(list1,list2,list3) print(id(list1),id(list2),id(list3)) 結果: [1,3] 16775288 16776768
可變資料型別與不可變資料型別
在python中哪些是可變資料型別,哪些是不可變資料型別。可變資料型別:列表list和字典dict;不可變資料型別:整型int、浮點型float、字串型string和元組tuple。
用一句話來概括上述過程就是:“python中的不可變資料型別,不允許變數的值發生變化,如果改變了變數的值,相當於是新建了一個物件,而對於相同的值的物件,在記憶體中則只有一個物件,內部會有一個引用計數來記錄有多少個變數引用這個物件;可變資料型別,允許變數的值發生變化,即如果對變數進行append、+=等這種操作後,只是改變了變數的值,而不會新建一個物件,變數引用的物件的地址也不會變化,不過對於相同的值的不同物件,在記憶體中則會存在不同的物件,即每個物件都有自己的地址,相當於記憶體中對於同值的物件儲存了多份,這裡不存在引用計數,是實實在在的物件。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。