標籤:int 簡單 區別 等等 包含 class highlight 基本資料 資料結構
一、概念引入
在進階語言中,變數是對記憶體及其地址的抽象。
對於python而言,python的一切變數都是對象,變數的儲存,採用了引用語義的方式,儲存的只是一個變數的值所在的記憶體位址,而不是這個變數的只本身。
引用語義:在python中,變數儲存的是對象(值)的引用,我們稱為引用語義。採用這種方式,變數所需的儲存空間大小一致,因為變數只是儲存了一個引用。也被稱為對象語義和指標語義。
值語義:有些語言採用的不是這種方式,它們把變數的值直接儲存在變數的儲存區裡,這種方式被我們稱為值語義,例如C語言,採用這種儲存方式,每一個變數在記憶體中所佔的空間就要根據變數實際的大小而定,無法固定下來。
由於python中的變數都是採用的引用語義,資料結構可以包含基礎資料類型,導致了在python中每個變數中都儲存了這個變數的地址,而不是值本身;
我們來看一張簡單易懂的圖理解一下python的引用語義和C語言值語義在記憶體中的儲存情況,左右兩個圖,分別表示了python中變數儲存與C語言中變數儲存區別:
對於複雜的資料結構來說,裡面的儲存的也只只是每個元素的地址而已,下面給出基礎類型和資料結構類型變數重新賦值的儲存變化:
參考:http://www.cnblogs.com/Eva-J/p/5534037.html
二、各基礎資料型別 (Elementary Data Type)的地址儲存及改變情況
在python中的資料類型包括:bool、int、long、float、str、set、list、tuple、dict等等。我們可以大致將這些資料類型歸類為單一資料型別和複雜的資料結構。
如果一個資料類型,可以將其他資料類型作為自己的元素,那麼我們就稱該資料類型為資料結構。資料結構的分類有很多種,但是在Python中常用的只有集合、序列和映射三種結構。對應python中的set、list(tuple、str)、dict;常用的資料類型有int、long、float、bool、str等類型。
由於python中的變數都是採用的引用語義,資料結構可以包含基礎資料類型,導致了在python中資料的儲存是這種情況,每個變數中都儲存了這個變數的地址,而不是值本身;對於複雜的資料結構來說,裡面的儲存的也只只是每個元素的地址而已。
1 my_str = "ways"2 my_list = [0,1,2,["a","b", "c"]]3 my_dic = {"name":"ways", "age":16}4 print(id(my_str))5 print(id(my_list))6 print(id(my_list[0]),id(my_list[1]),id(my_list[2]),id(my_list[3]))7 print(id(my_dic),id(my_dic["name"]),id(my_dic["age"]))
輸出:
2131810169664
2131811101448
1837680272 1837680304 1837680336 2131810205832
2131810159136 2131810169664 1837680784
1.資料類型重新初始化對python語義引用的影響
1 a = 12342 print(id(a))3 a = 4564 print(id(a))5 輸出:6 19479236810407 1947919757008
變數的每一次初始化,都開闢了一個新的空間,將新內容的地址賦值給變數。
2.資料結構內部元素變化重對python語義引用的影響
1 >>> my_list = [1,2,3,4] 2 >>> print(id(my_list)) 3 2250887009480 4 >>> my_list.append("add") 5 >>> print(id(my_list)) 6 2250887009480 7 >>> my_list.pop() 8 ‘add‘ 9 >>> print(id(my_list))10 225088700948011 >>> print(id(my_list[0]))12 185439198413 >>> my_list[0]="ways"14 >>> print(id(my_list[0]))15 225088701772816 >>> my_list = [3333,44444,55555]17 >>> print(id(my_list))18 2250887008776
當對列表中的元素進行一些增刪改的操作的時候,是不會影響到my_list列表本身對於整個列表地址的,只會改變其內部元素的地址引用。可是當我們對於一個列表重新初始化(賦值)的時候,就給my_list這個變數重新賦予了一個地址,覆蓋了原本列表的地址,這個時候,my_list列表的記憶體id就發生了改變
三、查看變數記憶體位址
>>> a = 1>>> print(id(a))>>>1473627824
四、淺copy
概念:淺拷貝:不管多麼複雜的資料結構,淺拷貝都只會copy一層
1 import copy2 source_date = [1,2,3,4,5,[10,11,12]]3 copy_date = copy.copy(source_date)4 print("source:", id(source_date))5 print("copy_date", id(copy_date))6 輸出:7 source: 20627400014808 copy_date 2062740002632
1 source_date.append("sourcedate") 2 copy_date.append("copydate") 3 print("source:", source_date) 4 print("copy_date",copy_date) 5 copy_date[5][0] =6666 6 print("source:", source_date) 7 print("copy_date",copy_date) 8 source_date[5][0] = ["ways"] 9 print("source:", source_date)10 print("copy_date",copy_date)11 source_date[5] = ["ways","alex"]12 print("source:", source_date)13 print("copy_date",copy_date)14 輸出:15 source: [1, 2, 3, 4, 5, [10, 11, 12], ‘sourcedate‘]16 copy_date [1, 2, 3, 4, 5, [10, 11, 12], ‘copydate‘]17 source: [1, 2, 3, 4, 5, [6666, 11, 12], ‘sourcedate‘]18 copy_date [1, 2, 3, 4, 5, [6666, 11, 12], ‘copydate‘]19 source: [1, 2, 3, 4, 5, [[‘ways‘], 11, 12], ‘sourcedate‘]20 copy_date [1, 2, 3, 4, 5, [[‘ways‘], 11, 12], ‘copydate‘]21 source: [1, 2, 3, 4, 5, [‘ways‘, ‘alex‘], ‘sourcedate‘]22 copy_date [1, 2, 3, 4, 5, [[‘ways‘], 11, 12], ‘copydate‘]
五、深copy
深拷貝會完全複製原變數相關的所有資料,在記憶體中產生一套完全一樣的內容,在這個過程中我們對這兩個變數中的一個進行任意修改都不會影響其他變數。
1 source_str = ["ways","tanks","yang",[1,2,3]] 2 copy_str = copy.deepcopy(source_str) 3 print(id(source_str),id(source_str[0]),id(source_str[3]),id(source_str[3][0])) 4 print(id(copy_str),id(copy_str[0]),id(copy_str[3]),id(copy_str[3][0])) 5 source_str[3][1] = 6666 6 print(id(source_str),id(source_str[0]),id(source_str[3]),id(source_str[3][1])) 7 print(id(copy_str),id(copy_str[0]),id(copy_str[3]),id(copy_str[3][1])) 8 輸出: 9 2354768160392 2354767917832 2354768160584 183361707210 2354768160328 2354767917832 2354768160200 183361707211 2354768160392 2354767917832 2354768160584 235473355950412 2354768160328 2354767917832 2354768160200 1833617104
六、總結
- Python中對象的賦值都是進行對象引用(記憶體位址)傳遞
- 使用copy.copy(),可以進行對象的淺拷貝,它複製了對象,但對於對象中的元素,依然使用原始的引用.
- 如果需要複製一個容器物件,以及它裡面的所有元素(包含元素的子項目),可以使用copy.deepcopy()進行深拷貝
python深淺拷貝