python默认深拷贝_Python 深拷贝与浅拷贝
首先分享Python里面的數(shù)據(jù)類型
1、不可變類型:Number(數(shù)字)、String(字符串)、Tuple(元組)。
不可變數(shù)據(jù)類型在第一次聲明賦值的時(shí)候, 會(huì)在內(nèi)存中開辟一塊空間, 用來(lái)存放這個(gè)變量被賦的值,? 而這個(gè)變量實(shí)際上存儲(chǔ)的, 并不是被賦予的這個(gè)值, 而是存放這個(gè)值所在空間的內(nèi)存地址, 通過這個(gè)地址, 變量就可以在內(nèi)存中取出數(shù)據(jù)了. 所謂不可變就是說(shuō), 我們不能改變這個(gè)數(shù)據(jù)在內(nèi)存中的值, 所以當(dāng)我們改變這個(gè)變量的賦值時(shí), 只是在內(nèi)存中重新開辟了一塊空間, 將這一條新的數(shù)據(jù)存放在這一個(gè)新的內(nèi)存地址里, 而原來(lái)的那個(gè)變量就不在引用原數(shù)據(jù)的內(nèi)存地址而轉(zhuǎn)為引用新數(shù)據(jù)的內(nèi)存地址了.
如圖:
In [11]: a = 1 #int為不可變類型,賦值
?
In [12]: id(a) #查看a地址
Out[12]: 4541615920In [13]: id(1) #查看數(shù)字1的地址
Out[13]: 4541615920?
In [14]: a = 2 #為a重新賦值
?
In [15]: id(a) #查看a地址,指向新的內(nèi)存地址
Out[15]: 4541615952?
In [16]: id(2)
Out[16]: 4541615952?
In [17]: id(1)
Out[17]: 4541615920
In [28]: a = "hello" #為a賦值 hello
?
In [29]: b = a #將a賦值給a
?
In [30]: id(a)
Out[30]: 4572905712?
In [31]: id(b) #通過查看a和b的地址,說(shuō)明a和b指向同一個(gè)地址
Out[31]: 4572905712?
In [32]: b = "hi" #為b賦值 hi
?
In [33]: a #查看a未被修改
Out[33]: 'hello'?
In [34]: id(a) #查看a地址未發(fā)生修改
Out[34]: 4572905712?
In [35]: id(b) #查看b指向新的地址,說(shuō)明b=a時(shí),是將a的引用指向b
Out[35]: 4544178736
b=a直接賦值時(shí),默認(rèn)是淺拷貝傳遞對(duì)象的引用而已,原始數(shù)據(jù)若為不可變類型時(shí),被賦值的b改變時(shí),相當(dāng)于在內(nèi)存中重新開辟了一塊空間, 將這一條新的數(shù)據(jù)存放在這一個(gè)新的內(nèi)存地址里, 而原來(lái)的那個(gè)變量就不在引用原數(shù)據(jù)的內(nèi)存地址而轉(zhuǎn)為引用新數(shù)據(jù)的內(nèi)存地址了.
2、可變類型:Set(集合)、List(列表)、Dictionary(字典)。
當(dāng)數(shù)據(jù)類型對(duì)應(yīng)的變量的值發(fā)生改變時(shí),它對(duì)應(yīng)的內(nèi)存地址也會(huì)發(fā)生改變,即當(dāng)?e?=?[1,2]?時(shí),是e指向列表[1,2]對(duì)象,而不是將e指向列表[1,2]的地址
如圖:
In [10]: e = [1,2]
?
In [11]: id(e)
Out[11]: 4408548080?
In [12]: id([1,2]) #e指向[1,2]對(duì)象,而不是[1,2]的地址
Out[12]: 4408714656
In [10]: e = [1,2] #給變量e賦值可變類型列表[1,2]
?
In [11]: id(e) #查看e地址
Out[11]: 4408548080?
In [12]: id([1,2]) #查看列表[1,2]地址
Out[12]: 4408714656?
In [13]: f = e #將e賦值給f,兩者共享同一個(gè)列表[1,2]對(duì)象
?
In [14]: id(f) #查看f地址,其實(shí)是將c指向于e的引用地址,而非列表[1,2]的實(shí)際地址
Out[14]: 4408548080?
In [15]: e[0] = 11 #通過e修改列表內(nèi)元素
?
In [16]: e
Out[16]: [11, 2]
?
In [17]: f #查看f中對(duì)應(yīng)元素同樣被修改,驗(yàn)證e和f指向一個(gè)引用對(duì)象,說(shuō)明f=e時(shí),是將e的對(duì)象的地址指向f
Out[17]: [11, 2]
f?=?e直接賦值時(shí),默認(rèn)是淺拷貝傳遞對(duì)象的引用而已,原始數(shù)據(jù)e若為可變類型發(fā)生變化,被賦值的f也會(huì)做相同的改變。
3. 淺拷貝
淺拷貝是對(duì)于一個(gè)對(duì)象的頂層拷貝
通俗的理解是:拷貝了引用,并沒有拷貝內(nèi)容
In [36]: a = [1,2]
?
In [37]: b =a
?
In [38]: id(a)
Out[38]: 4573291056?
In [39]: id(b) #淺拷貝,a和b地址相同,說(shuō)明b=a是對(duì)a引用的拷貝
Out[39]: 4573291056
通過上面的結(jié)果,說(shuō)明當(dāng)給一個(gè)變量賦值時(shí)。其實(shí)就是講數(shù)據(jù)的引用復(fù)制了一份給另外一個(gè)變量 ,就是屬于簡(jiǎn)單的淺拷貝
In [36]: a = [1,2]
?
In [37]: b =a
?
In [38]: id(a)
Out[38]: 4573291056?
In [39]: id(b)
Out[39]: 4573291056?
In [40]: a[0] = 11?
In [41]: a #a中元素被修改
Out[41]: [11, 2]
?
In [42]: b #b中元素被修改
Out[42]: [11, 2]
通過上面的結(jié)果,說(shuō)明通過任何一個(gè)引用修改可變變量之后,另外一個(gè)變量的值也發(fā)生了變化。
In [24]: g = [2,3]
?
In [25]: h = copy.copy(g) #淺拷貝
?
In [26]: id(g)
Out[26]: 4409269536?
In [27]: id(h)
Out[27]: 4408716176?
In [28]: id([2,3])
Out[28]: 4408685824?
In [30]: id(2) #獲取2的地址
Out[30]: 4378861392?
In [31]: id(g[0]) #獲取g[0]位置的地址
Out[31]: 4378861392?
In [32]: id(h[0]) #獲取h[0]位置的地址
Out[32]: 4378861392
通過上面的結(jié)果,說(shuō)明淺拷貝只是對(duì)外層引用的拷貝,內(nèi)層地址一樣。
In [33]: a = [11,22]
?
In [34]: b = [33,44]
?
In [35]: c =[a,b]
?
In [36]: id(a)
Out[36]: 4408713536?
In [37]: id(b)
Out[37]: 4408547680?
In [38]: id(c)
Out[38]: 4408615712?
In [39]: d = copy.copy(c) #對(duì)c進(jìn)行淺拷貝,得到d
?
In [40]: id(d) #查看d地址
Out[40]: 4409421248?
In [41]: id(d[0]) #查看d[0]位置元素地址,與a地址相同,說(shuō)明只進(jìn)行外層拷貝
Out[41]: 4408713536?
In [42]: id(d[1]) #查看d[1]位置元素地址,與b地址相同,說(shuō)明只進(jìn)行外層拷貝
Out[42]: 4408547680?
In [43]: a.append(55) #給a列表添加元素
?
In [44]: c #查看c中元素也發(fā)生變化
Out[44]: [[11, 22, 55], [33, 44]]
?
In [45]: d #查看d中元素也發(fā)生變化,說(shuō)明是對(duì)外層的拷貝
Out[45]: [[11, 22, 55], [33, 44]]
?
In [46]: d.append(66) #給d中添加元素
?
In [47]: d #查看d中元素發(fā)生變化
Out[47]: [[11, 22, 55], [33, 44], 66]
?
In [48]: c #查看c中元素未發(fā)生變化,說(shuō)明d未外層拷貝
Out[48]: [[11, 22, 55], [33, 44]]
通過上面的結(jié)果,說(shuō)明淺拷貝只是對(duì)外層引用的拷貝,內(nèi)層地址一樣,修改外層,拷貝的新對(duì)象不會(huì)發(fā)生變化,修改內(nèi)層元素,拷貝的新對(duì)象會(huì)發(fā)生變化。
4. 深拷貝
深拷貝是對(duì)于一個(gè)對(duì)象所有層次的拷貝(遞歸), 所以原始對(duì)象的改變不會(huì)造成深拷貝里任何子元素的改變
In [61]: a = [11,22]
?
In [62]: b = [33,44]
?
In [63]: c =[a,b]
?
In [64]: c
Out[64]: [[11, 22], [33, 44]]
?
In [65]: d = copy.deepcopy(c) #深拷貝得到d
?
In [66]: d
Out[66]: [[11, 22], [33, 44]]
?
In [67]: f = copy.copy(c) #淺拷貝得到f
?
In [68]: f
Out[68]: [[11, 22], [33, 44]]
?
In [69]: a.append(55) #a中添加元素55
?
In [70]: d #深拷貝的d中沒有修改,說(shuō)明是對(duì)內(nèi)層也進(jìn)行copy
Out[70]: [[11, 22], [33, 44]]
?
In [71]: f #淺拷貝的f中發(fā)生變化,說(shuō)明是只對(duì)外層進(jìn)行了copy
Out[71]: [[11, 22, 55], [33, 44]]
總結(jié)
以上是生活随笔為你收集整理的python默认深拷贝_Python 深拷贝与浅拷贝的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 多线程的同步问题_java多线
- 下一篇: websocket python爬虫_p