在python中,對象賦值實際上是對象的引用。當創建一個對象,然後把它賦給另一個變量的時候,python並沒有拷貝這個對象,而只是拷貝了這個對象的引用。以下分兩個思路來分別理解淺拷貝和深拷貝:
- 利用切片操作和工廠方法list方法拷貝
- 利用copy中的deepcopy方法進行拷貝
1、利用切片操作和工廠方法list方法拷貝
代碼場景:有一個小夥jack,tom通過切片操作拷貝jack,anny通過工廠方法拷貝jack。
>>> jack = ['jack', ['age', 20]] >>> tom = jack[:] >>> anny = list(jack)
來看下三者的id值:
>>> print id(jack), id(tom), id(anny) 144846988 144977164 144977388
從id值來看,三者是不同的對象。爲tom和anny重新命名爲各自的名稱:
>>> tom[0] = 'tom' >>> anny[0] = 'anny' >>> print jack, tom, anny ['jack', ['age', 20]] ['tom', ['age', 20]] ['anny', ['age', 20]]
從這裏來看一切正常,可是anny只有18歲,重新爲anny定義歲數。
>>> anny[1][1] = 18 >>> print jack, tom, anny ['jack', ['age', 18]] ['tom', ['age', 18]] ['anny', ['age', 18]]
這時候奇怪的事情發生了,jack、tom、anny的歲數都發生了改變,都變成了18了。jack、tom、anny他們應當都是不同的對象,怎麼會互相影響呢?看下jack,tom,anny的內部元素每個元素id:
>>> [id(x) for x in jack] [3073896320L, 3073777580L] >>> [id(x) for x in tom] [144870744, 3073777580L] >>> [id(x) for x in anny] [144977344, 3073777580L]
恍然大悟,原來jack、tom、anny的歲數元素指向的是同一個元素。修改了其中一個,當然影響其他人了。那爲什麼修改名稱沒影響呢?原來在python中字符串不可以修改,所以在爲tom和anny重新命名的時候,會重新創建一個’tom’和’anny’對象,替換舊的’jack’對象。爲了便於理解,我畫了一個草圖:
2、利用copy中的deepcopy方法進行拷貝
爲了讓他們之間不互相影響,用deepcopy來試試
>>> jack = ['jack', ['age', '20']] >>> import copy >>> tom = copy.deepcopy(jack) >>> anny = copy.deepcopy(jack)
根據第一個思路進行重命名,重定歲數操作:
>>> tom[0] = 'tom' >>> anny[0] = 'anny' >>> print jack, tom, anny ['jack', ['age', '20']] ['tom', ['age', '20']] ['anny', ['age', '20']] >>> anny[1][1] = 18 >>> print jack, tom, anny ['jack', ['age', '20']] ['tom', ['age', '20']] ['anny', ['age', 18]]
這時候他們之間就不會互相影響了。打印出每個人的內部元素每個id:
>>> [id(x) for x in jack] [139132064, 3073507244L] >>> [id(x) for x in tom] [139137464, 139132204] >>> [id(x) for x in anny] [139141632, 139157548]
他們的內部元素也都指向了不同的對象。
小結:
思路一:利用切片操作和工廠方法list方法拷貝就叫淺拷貝,只是拷貝了最外圍的對象本身,內部的元素都只是拷貝了一個引用而已。
思路二:利用copy中的deepcopy方法進行拷貝就叫做深拷貝,外圍和內部元素都進行了拷貝對象本身,而不是引用。
但是對於數字,字符串和其他原子類型對象等,沒有被拷貝的說法,即便是用深拷貝,查看id的話也是一樣的,如果對其重新賦值,也只是新創建一個對象,替換掉舊的而已。
轉載請註明:快樂編程 » python中的深拷貝和淺拷貝理解