十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊
量身定制 + 運(yùn)營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
Python賦值操作或函數(shù)參數(shù)傳遞,傳遞的永遠(yuǎn)是對象引用(即內(nèi)存地址),而不是對象內(nèi)容。在Python中一切皆對象,對象又分為可變(mutable)和不可變(immutable)兩種類型。對象拷貝是指在內(nèi)存中創(chuàng)建新的對象,產(chǎn)生新的內(nèi)存地址。當(dāng)頂層對象和它的子元素對象全都是immutable不可變對象時,不存在被拷貝,因為沒有產(chǎn)生新對象。淺拷貝(Shallow Copy),拷貝頂層對象,但不會拷貝內(nèi)部的子元素對象。深拷貝(Deep Copy),遞歸拷貝頂層對象,以及它內(nèi)部的子元素對象。
專業(yè)領(lǐng)域包括成都網(wǎng)站建設(shè)、做網(wǎng)站、成都做商城網(wǎng)站、微信營銷、系統(tǒng)平臺開發(fā), 與其他網(wǎng)站設(shè)計及系統(tǒng)開發(fā)公司不同,成都創(chuàng)新互聯(lián)的整合解決方案結(jié)合了幫做網(wǎng)絡(luò)品牌建設(shè)經(jīng)驗和互聯(lián)網(wǎng)整合營銷的理念,并將策略和執(zhí)行緊密結(jié)合,為客戶提供全網(wǎng)互聯(lián)網(wǎng)整合方案。
Python中一切皆對象,對象就像一個塑料盒子, 里面裝的是數(shù)據(jù)。對象有不同類型,例如布爾型和整型,類型決定了可以對它進(jìn)行的操作。現(xiàn)實生活中的"陶器"會暗含一些信息(例如它可能很重且易碎,注意不要掉到地上)。
對象的類型還決定了它裝著的數(shù)據(jù)是允許被修改的變量(可變的mutable)還是不可被修改的常量(不可變的immutable)。你可以把不可變對象想象成一個透明但封閉的盒子:你可以看到里面裝的數(shù)據(jù),但是無法改變它。類似地,可變對象就像一個開著口的盒子,你不僅可以看到里面的數(shù)據(jù),還可以拿出來修改它,但你無法改變這個盒子本身,即你無法改變對象的類型。
對象拷貝是指在內(nèi)存中創(chuàng)建新的對象,產(chǎn)生新的內(nèi)存地址。
淺拷貝(Shallow Copy),拷貝頂層對象,但不會拷貝內(nèi)部的子元素對象。
2.1.1. 頂層是mutable,子元素全是immutable
當(dāng)頂層對象是mutable可變對象,但是它的子元素對象全都是immutable不可變對象時,如[1, 'world', 2]
① 創(chuàng)建列表對象并賦值給變量a
② 導(dǎo)入copy模塊,使用copy.copy()函數(shù)淺拷貝a,并賦值給變量b
③ 修改變量a的子元素a[0] = 3,由于整數(shù)是不可變對象,所以并不是修改1變?yōu)?,而是更改a[0]指向?qū)ο?
當(dāng)頂層對象是 mutable可變對象 ,但子元素也存在 mutable可變對象 時,如 [1, 2, ['hello','world']]
① 淺拷貝 copy.copy() 只拷貝了頂層對象,沒有拷貝子元素對象['hello','world'],即a[2]和b[2]指向同一個列表對象
② 修改a[2][1] = 'china',則b[2][1] = 'china'
當(dāng)頂層對象是immutable不可變對象,同時它的子元素對象也全都是immutable不可變對象時,如(1, 2, 3)
變量a與變量b指向的是同一個元組對象,沒有拷貝
當(dāng)頂層對象是immutable不可變對象時,但子元素存在mutable可變對象時,如(1, 2, ['hello','world'])
變量a與變量b指向的是相同的元組對象,并且a[2]與b[2]指向同一個列表,所以修改a[2][1]會影響b[2][1]
深拷貝(Deep Copy),遞歸拷貝頂層對象,以及它內(nèi)部的子元素對象
當(dāng)頂層對象是mutable可變對象,但是它的子元素對象全都是immutable不可變對象時,如[1, 'world', 2]
變量a與變量b指向不同的列表對象,修改a[0]只是將列表a的第一個元素重新指向新對象,不會影響b[0]
當(dāng)頂層對象是mutable可變對象,但子元素也存在mutable可變對象時,如[1, 2, ['hello','world']]
深拷貝既拷貝了頂層對象,又遞歸拷貝了子元素對象,所以a[2]與b[2]指向了兩個不同的列表對象(但是列表對象的子元素初始指定的字符串對象一樣),修改a[2][1] = 'china'后,它重新指向了新的字符串對象(內(nèi)存地址為140531581905808),不會影響到b[2][1]
當(dāng)頂層對象是immutable不可變對象,同時它的子元素對象也全都是immutable不可變對象時,如(1, 2, 3)
變量a與變量b指向的是同一個元組對象,不存在拷貝
當(dāng)頂層對象是immutable不可變對象時,但子元素存在mutable可變對象時,如(1, 2, ['hello','world'])
變量a與變量b指向的是不同的元組對象,同時a[2]與b[2]指向不同的列表對象,所以修改a[2][1]不會影響b[2][1]
使用=是賦值,即將列表對象的引用也賦值給變量b,可以將列表對象想像成一個盒子,變量a相當(dāng)于這個盒子上的標(biāo)簽,執(zhí)行b = a后,相當(dāng)于再在這個盒子上貼上b標(biāo)簽,a和b實際上指向的是同一個對象。因此,無論我們是通過a還是通過b來修改列表的內(nèi)容,其結(jié)果都會作用于雙方。
b/c/d都是a的復(fù)制,它們都指向了不同的列表對象,但是沒有拷貝子元素,a[2]和b[2]/c[2]/d[2]指向同一個列表, 相當(dāng)于淺拷貝的效果
使用分片[:]操作,a和b其實是指向同一個元組,而且沒有拷貝子元素,a[2]和b[2]也指向同一個列表,相當(dāng)于淺拷貝的效果
同列表類似,可以使用字典的copy()函數(shù)或者轉(zhuǎn)換函數(shù)dict()
變量a與變量b/c指向不同的字典,但是沒有拷貝子元素,a['jobs']和b['jobs']/c['jobs']指定同一個列表, 相當(dāng)于淺拷貝的效果
同列表類似,可以使用集合的copy()函數(shù)或者轉(zhuǎn)換函數(shù)set()
變量a與變量b/c指向不同的集合,而集合的元素必須是hashable,所以修改集合a不會影響到b/c
淺拷貝是對一個對象父級(外層)的拷貝,并不會拷貝子級(內(nèi)部),而深拷貝對一個對象是所有層次的拷貝(遞歸),內(nèi)部和外部都會被拷貝過來。
使用淺拷貝的時候,分為兩種情況。
第一種,如果最外層的數(shù)據(jù)類型是可變的,比如說列表,字典等,淺拷貝會開啟新的地址空間去存放。
第二種,如果最外層的數(shù)據(jù)類型是不可變的,比如元組,字符串等,淺拷貝對象的時候,還是引用對象的地址空間。
深拷貝也分兩種情況:
第一種,最外層數(shù)據(jù)類型可變。這個時候,內(nèi)部和外部的都會拷貝過來。
第二種,外層數(shù)據(jù)類型不可變,如果里面是可變數(shù)據(jù)類型,會新開辟地址空間存放。如果內(nèi)部數(shù)據(jù)類型不可變,才會如同淺拷貝一樣,是對地址的引用。
賦值(=),就是創(chuàng)建了對象的一個新的引用,修改其中任意一個變量都會影響到另一個。
淺拷貝:創(chuàng)建一個新的對象,但它包含的是對原始對象中包含項的引用(如果用引用的方式修改其中一個對象,另外一個也會修改改變){1,完全切片方法;2,工廠函數(shù),如list();3,copy模塊的copy()函數(shù)}
深拷貝:創(chuàng)建一個新的對象,并且遞歸的復(fù)制它所包含的對象(修改其中一個,另外一個不會改變){copy模塊的deep.deepcopy()函數(shù)}
在Python中對象的賦值(=)其實就是對象的引用。即:當(dāng)創(chuàng)建一個對象,把它賦值給另一個變量時,python并沒有拷貝這個對象,只是拷貝了這個對象的引用而已。
Python中對象的拷貝分為:淺拷貝(copy)和深拷貝(deepcopy)。
淺拷貝:拷貝了最外圍的對象本身,內(nèi)部的元素都只是拷貝了一個引用而已。也就是,將原對象在內(nèi)存中引用地址拷貝過來,然后讓新的對象指向這個地址??梢允褂谩?”或列表自帶的copy()函數(shù)(如list.copy()),或使用copy模塊的copy()函數(shù)。
深拷貝:外圍和內(nèi)部元素都進(jìn)行了拷貝對象本身,而不是引用。即把對象復(fù)制一遍,并且該對象中引用的其他對象也同時復(fù)制,完全得到一個新的一模一樣的對象,對新對象里的值進(jìn)行修改不會影響原有對象,新對象和原對象完全分離開。深拷貝只能使用copy模塊中deepcopy()函數(shù),使用前要導(dǎo)入:from copy import deepcopy。
Python中對象分為不可變對象 、可變對象。
不可變對象:一旦創(chuàng)建就不可修改的對象,例如:字符串、元組、數(shù)字
可變對象:可以修改的對象,例如:列表、字典。
其中Python中的切片可以應(yīng)用于:列表、元組、字符串,但不能應(yīng)用于字典。
而深淺拷貝,可應(yīng)用于序列(列表、元組、字符串),也可應(yīng)用于字典。
其中不可變對象,不管是深拷貝還是淺拷貝,地址值在拷貝后的值都是一樣的。
以下以元組(不可變類型)為例
從上述示例可以看出:
不可變對象類型,沒有被拷貝的說法,即便是用深拷貝,查看id的話也是一樣的,如果對其重新賦值,也只是新創(chuàng)建一個對象,替換掉舊的而已。
所以不可變類型,不管是深拷貝還是淺拷貝,地址值和拷貝后的值都是一樣的。
以下以列表(可變類型)為例
第一種方法:使用=號淺拷貝
輸出結(jié)果:
第二種方法:使用copy淺拷貝
輸出結(jié)果:
第三種方法:使用deepcopy深拷貝
輸出結(jié)果:
從上述示例可以看出:
=淺拷貝:值相等,地址相等
copy淺拷貝:值相等,地址不相等
deepcopy深拷貝:值相等,地址不相等
總結(jié):
1,深淺拷貝都是對源對象的復(fù)制,占用不同的內(nèi)存空間。
2,不可變類型的對象,對于深淺拷貝毫無影響,最終的地址值和值都是相等的。
3,可變類型的對象,使用=淺拷貝時, 值相等,地址相等,對新對象里的值進(jìn)行修改同時會影響原有對象;使用copy淺拷貝時值相等,地址不相等;使用deepcopy深拷貝時值相等,地址不相等??梢钥闯鲠槍勺冾愋蚦opy淺拷貝和deepcopy深拷貝,對新對象里的值進(jìn)行修改不會影響原有對象。