可以說Python沒有賦值,只有引用。你這樣相當(dāng)于創(chuàng)建了一個(gè)引用自身的結(jié)構(gòu),所以導(dǎo)致了無限循環(huán)。為了理解這個(gè)問題,有個(gè)基本概念需要搞清楚。
Python沒有「變量」,我們平時(shí)所說的變量其實(shí)只是「標(biāo)簽」,是引用。
python中,"a=b"表示的是對象a引用對象b,對象a本身沒有單獨(dú)分配內(nèi)存空間(重要:不是復(fù)制!),它指向計(jì)算機(jī)中存儲對象b的內(nèi)存。因此,要想將一個(gè)對象復(fù)制為另一個(gè)對象,不能簡單地用等號操作,要使用其它的方法。如序列類的對象是(列表、元組)要使用切片操作符(即':')來做復(fù)制。
在python進(jìn)行像b = a這樣的賦值時(shí),只會創(chuàng)建一個(gè)對a的新引用,使a的引用計(jì)數(shù)加1,而不會創(chuàng)建新的對象:
>>> a = 'xyz'>>> import sys>>> sys.getrefcount(a)3>>> b = a>>> sys.getrefcount(b)4>>> id(a)88292288L>>> id(b)88292288L
這樣,當(dāng)引用的對象是可變對象的時(shí)候(列表,字典,可變集合等),會產(chǎn)生意料之外的行為:
>>> a = [1, 2, 3, 4]>>> b = a>>> b.append(5)>>> a[1, 2, 3, 4, 5]
因?yàn)閍和b引用的是同一對象,改變其中一個(gè),另外一個(gè)也會隨之改變。當(dāng)我們想建立一個(gè)副本而不是引用時(shí),可以復(fù)制對象。
復(fù)制對象一般使用copy模塊:
>>> a = [1, 2, 3, 4]>>> import copy>>> b = copy.copy(a)>>> b.append(5)>>> b[1, 2, 3, 4, 5]>>> a[1, 2, 3, 4]
這樣就可以了,但這種復(fù)制是一種淺復(fù)制,復(fù)制的新對象中包含的是對原始對象中的項(xiàng)的引用,如果對象的項(xiàng)為可變對象,也會產(chǎn)生不可控行為:
>>> a = [1, [1, 2]]>>> b = copy.copy(a)>>> b[1].append(3)>>> b[1, [1, 2, 3]]>>> a[1, [1, 2, 3]]
這時(shí)候就要使用深復(fù)制了。深復(fù)制將創(chuàng)建一個(gè)新對象,并遞歸地復(fù)制它所包含的所有對象:
>>> a = [1, [1, 2]]>>> b = copy.deepcopy(a)>>> b[1].append(3)>>> b[1, [1, 2, 3]]>>> a[1, [1, 2]]
對于不可改變的對象而言(字符串,數(shù)字,元組)等,沒有必要拷貝,因?yàn)樗鼈兪遣豢筛淖兊模挥脫?dān)心會不經(jīng)意間改動了它們。拷貝操作也只會得到原對象:
>>> a = (1, 2, 3)>>> b = copy.copy(a)>>> a is bTrue
對于可變對象來(列表,字典,可變集合)來說,可以分別使用內(nèi)置函數(shù)list(),dict(),set()來進(jìn)行淺復(fù)制,速度是比使用copy模塊快的。
列表也可以使用切片進(jìn)行淺復(fù)制:
>>> a = [1, 2, 3, 4]>>> b = a[:]>>> a is bFalse>>> b[1, 2, 3, 4]
新聞熱點(diǎn)
疑難解答
圖片精選