這篇文章主要是對python中的數據進行認識,對於不少初學者來說,其實數據的認識是最重要的,也是最容易出錯的。本文結合數據與內存形態講解python中的數據,內容包括:python
(id函數:你能夠經過python的內置函數 id() 來查看對象的身份(identity),這個所謂的身份其實就是 對象 的內存地址)app
1、引用與對象:引用與對象的關係:
ide
#建立兩個對象
函數
name1='wupeiqi'
優化
name2='alex'
this
對象:當建立數據對象時,在內存中會保存對象的值,這個值就是對象本身;(字符串對象:」wupeiqi」)
引用:對象保存在內存空間,外部想要使用對象的值,須要使用引用,就是‘name1’,’name2’。內存會保存對象的引用數量,當某個對象的引用數量爲0時,對象會被回收。3d
2、可變數據類型與不可變數據類型
1,數據分類:code
這裏的可變不可變,是指內存中的那塊內容(value)是否能夠被改變。若是是不可變類型,在對對象自己操做的時候,必須在內存中新申請一塊區域(由於老區域不可變)。若是是可變類型,對對象操做的時候,不須要再在其餘地方申請內存,只須要在此對象後面連續申請(+/-)便可,也就是它的address會保持不變,但區域會變長或者變短。對象
(1)python中的不可變數據類型,不容許變量的值發生變化,若是改變了變量的值,至關因而新建了一個對象,而對於相同的值的對象,在內存中則只有一個對象,內部會有一個引用計數來記錄有多少個變量引用這個對象;
(2)可變數據類型,容許變量的值發生變化,即若是對變量進行append、+=等這種操做後,只是改變了變量的值,而不會新建一個對象,變量引用的對象的地址也不會變化,不過對於相同的值的不一樣對象,在內存中則會存在不一樣的對象,即每一個對象都有本身的地址,至關於內存中對於同值的對象保存了多份,這裏不存在引用計數,是實實在在的對象。」blog
2,不可變數據類型:不可變是指對象自己的值是不可變的(當你建立a=1整型對象,用a去引用它,內存中的對象1是不變得,當執行a=2時,只是從新建立了對象2,用a引用,若是1對象沒有其餘引用會被回收)
>>> x = 1
>>> id(x)
31106520
>>> y = 1
>>> id(y)
31106520
>>> x = 2
>>> id(x)
31106508
>>> y = 2
>>> id(y)
31106508
>>> z = y
>>> id(z)
31106508
解釋:這裏的不可變你們能夠理解爲x引用的地址處的值是不能被改變的,也就是31106520地址處的值在沒被垃圾回收以前一直都是1,不能改變,若是要把x賦值爲2,那麼只能將x引用的地址從31106520變爲31106508,至關於x = 2這個賦值又建立了一個對象,即2這個對象,而後x、y、z都引用了這個對象,因此int這個數據類型是不可變的,若是想對int類型的變量再次賦值,在內存中至關於又建立了一個新的對象,而再也不是以前的對象。從下圖中就能夠看到上面程序的過程。
3,可變對象:可變是指對象自己的值是可變的(list,dict對象的值實際上是引用了其餘對象,當改變對象的值時,實際上是引用了不一樣的對象)
>>> a = [1, 2, 3]
>>> id(a)
41568816
>>> a = [1, 2, 3]
>>> id(a)
41575088
>>> a.append(4)
>>> id(a)
41575088
>>> a += [2]
>>> id(a)
41575088
>>> a
[1, 2, 3, 4, 2]
解釋:(1)進行兩次a = [1, 2, 3]操做,兩次a引用的地址值是不一樣的,也就是說其實建立了兩個不一樣的對象,這一點明顯不一樣於不可變數據類型,因此對於可變數據類型來講,具備一樣值的對象是不一樣的對象,即在內存中保存了多個一樣值的對象,地址值不一樣。
(2)咱們對列表進行添加操做,分別a.append(4)和a += [2],發現這兩個操做使得a引用的對象值變成了上面的最終結果,可是a引用的地址依舊是41575088,也就是說對a進行的操做不會改變a引用的地址值,只是在地址後面又擴充了新的地址,改變了地址裏面存放的值,因此可變數據類型的意思就是說對一個變量進行操做時,其值是可變的,值的變化並不會引發新建對象,即地址是不會變的,只是地址中的內容變化了或者地址獲得了擴充。下圖對這一過程進行了圖示,能夠很清晰地看到這一過程。
3、引用傳遞與值傳遞:可變對象爲引用傳遞,不可變對象爲值傳遞。(函數傳值)
1,引用傳遞:當傳遞列表或者字典時,若是改變引用的值,就修改了原始的對象。
# 添加了一個string類型的元素添加到末尾
def ChangeList(lis):
lis.append('hello i am the addone')
print lis
return
lis = [1, 2, 3]
ChangeList(lis)
print lis
輸出:
[1,2,3, 'hello i am the addone']
[1,2, 3,'hello i am the addone']
2,值傳遞:當傳遞不可變對象時,若是改變引用的值,只是建立了不一樣的對象,原始對象並無改變。
def ChangeString(string):
string = 'i changed as this'
print string
return
string = 'hello world'
ChangeString(string)
print string
輸出:
i changed as this
hello world
4、深拷貝與淺拷貝:
copy.copy() 淺拷貝;copy.deepcopy() 深拷貝。淺拷貝是新建立了一個跟原對象同樣的類型,可是其內容是對原對象元素的引用。這個拷貝的對象自己是新的,但內容不是。拷貝序列類型對象(列表\元組)時,默認是淺拷貝。
1,賦值拷貝:
賦值,只是建立一個變量,該變量指向原來內存地址:n4 = n3 = n2 = n1 = 「123/’Wu’」
2,淺拷貝:在內存中只額外建立第一層數據
import copy
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n3 = copy.copy(n1)
import copy
a = [1,[[2,3],5],3]
b = a.copy() #copy.copy(a)
print(id(a[1]))
print(id(b[1]))
c = copy.deepcopy(a)
print(id(c[1]))
輸出:
3021497843400
3021497843400
3021497854728
3,深拷貝:在內存中將全部的數據從新建立一份(排除最後一層,即:python內部對字符串和數字的優化)
import copy
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}
n4 = copy.deepcopy(n1)