python為拷貝提供了copy模塊躯护。提供了兩種主要的copy方法,一種是普通的copy攀痊,另一種是deepcopy桐腌。我們稱前者是淺拷貝,后者為深拷貝苟径。
深淺拷貝一直是所有編程語言的重要知識(shí)點(diǎn)案站,下面我們就從內(nèi)存的角度來分析一下兩者的區(qū)別。
一棘街、淺拷貝
首先蟆盐,我們來了解一下淺拷貝。淺拷貝:不管多么復(fù)雜的數(shù)據(jù)結(jié)構(gòu)遭殉,淺拷貝都只會(huì)copy一層石挂。下面就讓我們看一張圖,來了解一下淺淺拷貝的概念恩沽。
看上面兩張圖誊稚,我們加入左圖表示的是一個(gè)列表sourcelist,sourcelist = ['str1','str2','str3','str4','str5',['str1','str2','str3','str4','str5']]罗心;
右圖在原有的基礎(chǔ)上多出了一個(gè)淺拷貝的copylist里伯,copylist = ['str1','str2','str3','str4','str5',['str1','str2','str3','str4','str5']];
sourcelist和copylist表面上看起來一模一樣渤闷,但是實(shí)際上在內(nèi)存中已經(jīng)生成了一個(gè)新列表疾瓮,copy了sourceLst,獲得了一個(gè)新列表飒箭,存儲(chǔ)了5個(gè)字符串和一個(gè)列表所在內(nèi)存的地址狼电。
我們看下面分別對(duì)兩個(gè)列表進(jìn)行的操作蜒灰,紅色的框框里面是變量初始化,初始化了上面的兩個(gè)列表肩碟;我們可以分別對(duì)這兩個(gè)列表進(jìn)行操作强窖,例如插入一個(gè)值,我們會(huì)發(fā)現(xiàn)什么呢削祈?如下所示:
從上面的代碼我們可以看出翅溺,對(duì)于sourceLst和copyLst列表添加一個(gè)元素,這兩個(gè)列表好像是獨(dú)立的一樣都分別發(fā)生了變化髓抑,但是當(dāng)我修改lst的時(shí)候咙崎,這兩個(gè)列表都發(fā)生了變化,這是為什么呢吨拍?我們就來看一張內(nèi)存中的變化圖:
我們可以知道sourceLst和copyLst列表中都存儲(chǔ)了一坨地址褪猛,當(dāng)我們修改了sourceLst1的元素時(shí),相當(dāng)于用'sourceChange'的地址替換了原來'str1'的地址羹饰,所以sourceLst的第一個(gè)元素發(fā)生了變化伊滋。而copyLst還是存儲(chǔ)了str1的地址,所以copyLst不會(huì)發(fā)生改變队秩。
當(dāng)sourceLst列表發(fā)生變化新啼,copyLst中存儲(chǔ)的lst內(nèi)存地址沒有改變,所以當(dāng)lst發(fā)生改變的時(shí)候刹碾,sourceLst和copyLst兩個(gè)列表就都發(fā)生了改變。
這種情況發(fā)生在字典套字典座柱、列表套字典迷帜、字典套列表,列表套列表色洞,以及各種復(fù)雜數(shù)據(jù)結(jié)構(gòu)的嵌套中戏锹,所以當(dāng)我們的數(shù)據(jù)類型很復(fù)雜的時(shí)候,用copy去進(jìn)行淺拷貝就要非常小心火诸。
二锦针、深拷貝
剛剛我們了解了淺拷貝的意義,但是在寫程序的時(shí)候置蜀,我們就是希望復(fù)雜的數(shù)據(jù)結(jié)構(gòu)之間完全copy一份并且它們之間又沒有一毛錢關(guān)系奈搜,應(yīng)該怎么辦呢?
我們引入一個(gè)深拷貝的概念盯荤,深拷貝——即python的copy模塊提供的另一個(gè)deepcopy方法馋吗。深拷貝會(huì)完全復(fù)制原變量相關(guān)的所有數(shù)據(jù),在內(nèi)存中生成一套完全一樣的內(nèi)容秋秤,在這個(gè)過程中我們對(duì)這兩個(gè)變量中的一個(gè)進(jìn)行任意修改都不會(huì)影響其他變量宏粤。下面我們就來試驗(yàn)一下脚翘。