直接賦值:其實(shí)就是對(duì)象的引用(別名)浅缸。
淺拷貝(copy):拷貝父對(duì)象轨帜,不會(huì)拷貝對(duì)象的內(nèi)部的子對(duì)象。
深拷貝(deepcopy): copy 模塊的 deepcopy 方法衩椒,完全拷貝了父對(duì)象及其子對(duì)象蚌父。
淺拷貝
總結(jié)一下,當(dāng)我們使用下面的操作的時(shí)候毛萌,會(huì)產(chǎn)生淺拷貝的效果:
使用切片[:]操作
使用工廠函數(shù)(如list/dir/set)
使用copy模塊中的copy()函數(shù)
深拷貝
對(duì)于對(duì)象中的元素苟弛,深拷貝都會(huì)重新生成一份(有特殊情況,下面會(huì)說(shuō)明)阁将,而不是簡(jiǎn)單的使用原始元素的引用(內(nèi)存地址)
拷貝的特殊情況
其實(shí)膏秫,對(duì)于拷貝有一些特殊情況:
對(duì)于非容器類(lèi)型(如數(shù)字、字符串做盅、和其他'原子'類(lèi)型的對(duì)象)沒(méi)有拷貝這一說(shuō)
也就是說(shuō)荔睹,對(duì)于這些類(lèi)型狸演,"obj is copy.copy(obj)" 、"obj is copy.deepcopy(obj)"
如果元組變量只包含原子類(lèi)型對(duì)象僻他,則不能深拷貝
對(duì)象的賦值和拷貝宵距,以及它們之間的差異:
Python中對(duì)象的賦值都是進(jìn)行對(duì)象引用(內(nèi)存地址)傳遞
使用copy.copy(),可以進(jìn)行對(duì)象的淺拷貝吨拗,它復(fù)制了對(duì)象满哪,但對(duì)于對(duì)象中的元素,依然使用原始的引用.
如果需要復(fù)制一個(gè)容器對(duì)象劝篷,以及它里面的所有元素(包含元素的子元素)哨鸭,可以使用copy.deepcopy()進(jìn)行深拷貝
對(duì)于非容器類(lèi)型(如數(shù)字、字符串娇妓、和其他'原子'類(lèi)型的對(duì)象)沒(méi)有被拷貝一說(shuō)
如果元組變量只包含原子類(lèi)型對(duì)象像鸡,則不能深拷貝。
Python的每個(gè)對(duì)象都分為可變和不可變哈恰,主要的核心類(lèi)型中只估,數(shù)字、字符串着绷、元組是不可變的蛔钙,列表、字典是可變的荠医。
對(duì)不可變類(lèi)型的變量重新賦值吁脱,實(shí)際上是重新創(chuàng)建一個(gè)不可變類(lèi)型的對(duì)象,并將原來(lái)的變量重新指向新創(chuàng)建的對(duì)象(如果沒(méi)有其他變量引用原有對(duì)象的話(huà)(即引用計(jì)數(shù)為0)彬向,原有對(duì)象就會(huì)被回收)兼贡。
不可變類(lèi)型以int類(lèi)型為例:
實(shí)際上 i += 1 并不是真的在原有的int對(duì)象上+1,而是重新創(chuàng)建一個(gè)value為6的int對(duì)象娃胆,i引用自這個(gè)新的對(duì)象紧显。
通過(guò)id函數(shù)查看變量i的內(nèi)存地址進(jìn)行驗(yàn)證
可以看到執(zhí)行 i += 1 時(shí),內(nèi)存地址都會(huì)變化缕棵,因?yàn)閕nt 類(lèi)型是不可變的。
再改改代碼涉兽,但多個(gè)int類(lèi)型的變量值相同時(shí)招驴,看看它們內(nèi)存地址是否相同。
對(duì)于不可變類(lèi)型int枷畏,無(wú)論創(chuàng)建多少個(gè)不可變類(lèi)型别厘,只要值相同,都指向同個(gè)內(nèi)存地址拥诡。同樣情況的還有比較短的字符串触趴。
對(duì)于其他類(lèi)型則不同氮发,以浮點(diǎn)類(lèi)型為例,從代碼運(yùn)行結(jié)果可以看出它是個(gè)不可變類(lèi)型:對(duì)i的值進(jìn)行修改后冗懦,指向新的內(nèi)存地址爽冕。
修改代碼聲明兩個(gè)相同值的浮點(diǎn)型變量,查看它們的id披蕉,發(fā)現(xiàn)它們并不是指向同個(gè)內(nèi)存地址颈畸,這點(diǎn)和int類(lèi)型不同(這方面涉及Python內(nèi)存管理機(jī)制,Python對(duì)int類(lèi)型和較短的字符串進(jìn)行了緩存没讲,無(wú)論聲明多少個(gè)值相同的變量眯娱,實(shí)際上都指向同個(gè)內(nèi)存地址。)爬凑。
可變類(lèi)型的話(huà)扛吞,以list為例。
list在append之后兽愤,還是指向同個(gè)內(nèi)存地址抡爹,因?yàn)閘ist是可變類(lèi)型,可以在原處修改吱抚。
改改代碼百宇,當(dāng)存在多個(gè)值相同的不可變類(lèi)型變量時(shí),看看它們是不是跟可變類(lèi)型一樣指向同個(gè)內(nèi)存地址
從運(yùn)行結(jié)果可以看出秘豹,雖然a携御、b的值相同,但是指向的內(nèi)存地址不同既绕。我們也可以通過(guò)b = a 的賦值語(yǔ)句啄刹,讓他們指向同個(gè)內(nèi)存地址:
這個(gè)時(shí)候需要注意,因?yàn)閍凄贩、b指向同個(gè)內(nèi)存地址誓军,而a、b的類(lèi)型都是List疲扎,可變類(lèi)型昵时,對(duì)a、b任意一個(gè)List進(jìn)行修改椒丧,都會(huì)影響另外一個(gè)List的值壹甥。
代碼中,b變量append(4)壶熏,對(duì)a變量也是影響的句柠。輸出他們的內(nèi)存地址,還是指向同個(gè)內(nèi)存地址。
我們?cè)谇把岳锩嬗刑岬降哪莻€(gè)奇怪的問(wèn)題溯职,很顯然精盅,那是共享了字符串的字面量,這種Cpython里面一個(gè)優(yōu)化策略谜酒,叫駐留(interning).CPython 還會(huì)在小的整數(shù)上使用這個(gè)優(yōu)化措施叹俏,防止重復(fù)的創(chuàng)建”熱門(mén)“數(shù)字,比如0甚带,-1她肯,和42等等,但是CPython不會(huì)駐留所有的字符串和整數(shù)鹰贵。比如如下的代碼
所以千萬(wàn)不要依賴(lài)字符串或者整數(shù)的駐留晴氨!比較字符串或者整數(shù)是否相等的時(shí),應(yīng)該使用== 而不是is. 駐留是python 解釋器內(nèi)部使用的一個(gè)特性
python函數(shù)的參數(shù)傳遞
當(dāng)傳過(guò)來(lái)的是可變類(lèi)型(list,dict)時(shí)碉输,我們?cè)诤瘮?shù)內(nèi)部修改就會(huì)影響函數(shù)外部的變量籽前。而傳入的是不可變類(lèi)型時(shí)在函數(shù)內(nèi)部修改改變量并不會(huì)影響函數(shù)外部的變量,因?yàn)樾薷牡臅r(shí)候會(huì)先復(fù)制一份再修改敷钾。
python使用的內(nèi)存回收機(jī)制是計(jì)數(shù)器回收枝哄,就是每塊內(nèi)存上有一個(gè)計(jì)數(shù)器,表示當(dāng)前有多少個(gè)對(duì)象指向該內(nèi)存阻荒。每當(dāng)一個(gè)變量不再使用時(shí)挠锥,就讓該計(jì)數(shù)器-1,有新對(duì)象指向該內(nèi)存時(shí)就讓計(jì)數(shù)器+1侨赡,當(dāng)計(jì)時(shí)器為0時(shí)蓖租,就可以收回這塊內(nèi)存了
值傳遞:表示傳遞直接傳遞變量的值,把傳遞過(guò)來(lái)的變量的值復(fù)制到形參中羊壹,這樣在函數(shù)內(nèi)部的操作不會(huì)影響到外部的變量
引用傳遞:我個(gè)人覺(jué)得可以把引用理解為一個(gè)箭頭蓖宦,這個(gè)箭頭指向某塊內(nèi)存地址,而引用傳遞油猫,傳遞過(guò)來(lái)的就是這個(gè)箭頭稠茂,當(dāng)你修改內(nèi)容的時(shí)候,就是修改這個(gè)箭頭所指向的內(nèi)存地址中的內(nèi)容情妖,因?yàn)橥獠恳彩侵赶蜻@個(gè)內(nèi)存中的內(nèi)容的睬关,所以,在函數(shù)內(nèi)部修改就會(huì)影響函數(shù)外部的內(nèi)容毡证。
在Python中一切都是對(duì)象电爹。
Python中對(duì)象包含的三個(gè)基本要素,分別是:id(身份標(biāo)識(shí))情竹、type(數(shù)據(jù)類(lèi)型)和value(值)。對(duì)象之間比較是否相等可以用==,也可以用is秦效。
is和==都是對(duì)對(duì)象進(jìn)行比較判斷作用的雏蛮,但對(duì)對(duì)象比較判斷的內(nèi)容并不相同。下面來(lái)看看具體區(qū)別在哪?
is比較的是兩個(gè)對(duì)象的id值是否相等阱州,也就是比較兩個(gè)對(duì)象是否為同一個(gè)實(shí)例對(duì)象挑秉,是否指向同一個(gè)內(nèi)存地址。
==比較的是兩個(gè)對(duì)象的內(nèi)容是否相等苔货,默認(rèn)會(huì)調(diào)用對(duì)象的__eq__()方法
為什么256時(shí)相同犀概, 而1000時(shí)不同?
因?yàn)槌鲇趯?duì)性能的考慮夜惭,Python內(nèi)部做了很多的優(yōu)化工作姻灶,對(duì)于整數(shù)對(duì)象,Python把一些頻繁使用的整數(shù)對(duì)象緩存起來(lái)诈茧,保存到一個(gè)叫small_ints的鏈表中产喉,在Python的整個(gè)生命周期內(nèi),任何需要引用這些整數(shù)對(duì)象的地方敢会,都不再重新創(chuàng)建新的對(duì)象曾沈,而是直接引用緩存中的對(duì)象。Python把這些可能頻繁使用的整數(shù)對(duì)象規(guī)定在范圍[-5, 256]之間的小對(duì)象放在small_ints中鸥昏,但凡是需要用些小整數(shù)時(shí)塞俱,就從這里面取,不再去臨時(shí)創(chuàng)建新的對(duì)象吏垮。