首先以一個例子來講明一下:定義變量a = 1,使b = a。開始的狀況下打印a與b都爲1(顯而易見,哈哈)數據結構
可是接下來,咱們作一下改動,令 a = 222,再打印a與b。函數
咦?說好的b = a呢?!怎麼不同了呢?spa
這裏直接揭曉答案:3d
如上圖所示,a = 1操做實際上是將變量a 指向了數字1的內存地址,當進行b=a操做時,並非將a的值直接賦值給b,而是直接把變量b指向了1的內存地址。當進行a = 222時,程序又將變量a指向了222的內存地址,而此時b指向的仍然是1的內存地址,所以最終打印出來的a=222,而b=1。blog
咱們能夠用下面方法來驗證:內存
id()方法 能夠獲得變量以及其餘數據類型的內存地址,從上圖咱們能夠看到id(a)與id(b)相等,說明在進行b=a操做時,程序進行的是將變量b指向數字1的內存地址的操做。容器
這樣就比較好理解了,當進行a = 222操做的時候,a指向了222的內存地址,而此時b仍然指向的是1的內存地址,因此打印出來的值也不同了:變量
2.1列表的賦值:數據類型
這裏咱們仍是以一個例子來進行說明:程序
一開始固然是一派和諧,嘿嘿!可是,當咱們試圖改變l1的時候,你會發現:
當咱們將l1後面追加數字666後,打印出來的l1與l2居然同樣!這與上面的結果不一樣。爲何會是這樣的呢?
列表與變量不一樣的是:當把列表[1,2,3,4,5]賦給l1的時候,l1指向的其實只是這個「列表」的內存地址,而列表中的每一個元素是有本身獨立的內存地址的,與這個列表無關。而後咱們進行l2 = l1的操做時,程序執行的實際上是「將l2指向了l1指向的列表的內存地址」。
所以,不論是l1仍是l2,他們都只是指向了這個列表「容器」的地址,這個「容器」中有什麼甚至作何種改變他們是不知道的。因此咱們把列表後面追加數字666後,l1與l2指向的這個「容器」裏裝的「元素」是如出一轍的~
咱們還能夠用id()進行驗證:
這裏能夠看到l1與l2的內存地址一致。
2.2 列表的淺拷貝:
這裏仍是以一個例子開頭:
這裏當咱們進行l2 = l1.copy()的淺拷貝操做時,咱們會發現程序爲l2新建了一個內存空間。而後咱們再來進行改變操做:
當咱們進行l1[3] = 666後,僅改變了l1裏元素的值,l2仍然不變。這是由於列表中每一個元素的內存地址是與列表自己的內存地址不一樣的,因此當l1與l2指向了不一樣的內存地址的列表的時候,改變l1中「元素」的值l2仍然不變。這裏咱們能夠看看l1[3]與l2[3]的id就知道了:
能夠看出l1[3]的內存地址與l2[3]的內存地址不一樣,所以改變l1[3]的值不會影響l2[3]。
可是若是咱們換一個數據結構(列表嵌套列表):
這裏咱們將l1的l1[4]改爲了一個列表,當把l1淺拷貝給l2後,在l1與l2中是將[5,6]這個總體列表當成了原列表中的「元素」來對待的,因此l1[4]的id與l2[4]的id是相同列表的id,當咱們進行l1[4][0] = 666時,因爲l1[4]與l2[4]指向的是相同的列表,因此打印出的值是同樣的:
能夠看出l1[4]的id與l2[4]的id是相同列表的id,因爲內存地址相同因此改變其中的一個,另外的一個會跟着改變。
深拷貝,顧名思義固然是拷貝變量與原變量是獨立存在的,這裏直接上代碼演示:
如上圖所示,咱們須要先導入copy模塊來進行深拷貝,函數內用copy.deepcopy()方法進行實現。拷貝出來的列表是獨立存在的個體。
可是深拷貝在用的時候須要注意,因爲拷貝的變量是獨立存在的,因此它也會佔用內存空間。若是被拷貝的數據量很大(好比佔2g),那麼拷貝後的數據總量將翻倍(變成4g),用的時候先規劃好空