當前位置:成語大全網 - 新華字典 - python 為什麽有深拷貝淺拷貝

python 為什麽有深拷貝淺拷貝

在寫Python過程中,經常會遇到對象的拷貝,如果不理解淺拷貝和深拷貝的概念,妳的代碼就可能出現壹些問題。所以,在這裏按個人的理解談談它們之間的區別。

壹、賦值(assignment)

在《Python FAQ1》壹文中,對賦值已經講的很清楚了,關鍵要理解變量與對象的關系。

12345

>>> a = [1, 2, 3]>>> b = a>>> print(id(a), id(b), sep='\n')139701469405552139701469405552

在Python中,用壹個變量給另壹個變量賦值,其實就是給當前內存中的對象增加壹個“標簽”而已。

如上例,通過使用內置函數 id() ,可以看出 a 和 b 指向內存中同壹個對象。a is b會返回 True 。

二、淺拷貝(shallow copy)

註意:淺拷貝和深拷貝的不同僅僅是對組合對象來說,所謂的組合對象就是包含了其它對象的對象,如列表,類實例。而對於數字、字符串以及其它“原子”類型,沒有拷貝壹說,產生的都是原對象的引用。

所謂“淺拷貝”,是指創建壹個新的對象,其內容是原對象中元素的引用。(拷貝組合對象,不拷貝子對象)

常見的淺拷貝有:切片操作、工廠函數、對象的copy()方法、copy模塊中的copy函數。

12345678910

>>> a = [1, 2, 3]>>> b = list(a)>>> print(id(a), id(b)) # a和b身份不同140601785066200 140601784764968>>> for x, y in zip(a, b): # 但它們包含的子對象身份相同... print(id(x), id(y))... 140601911441984 140601911441984140601911442016 140601911442016140601911442048 140601911442048

從上面可以明顯的看出來,a 淺拷貝得到 b,a 和 b 指向內存中不同的 list 對象,但它們的元素卻指向相同的 int 對象。這就是淺拷貝!

三、深拷貝(deep copy)

所謂“深拷貝”,是指創建壹個新的對象,然後遞歸的拷貝原對象所包含的子對象。深拷貝出來的對象與原對象沒有任何關聯。

深拷貝只有壹種方式:copy模塊中的deepcopy函數。

1234567891011

>>> import copy>>> a = [1, 2, 3]>>> b = copy.deepcopy(a)>>> print(id(a), id(b))140601785065840 140601785066200>>> for x, y in zip(a, b):... print(id(x), id(y))... 140601911441984 140601911441984140601911442016 140601911442016140601911442048 140601911442048

看了上面的例子,有人可能會疑惑:

為什麽使用了深拷貝,a和b中元素的id還是壹樣呢?

答:這是因為對於不可變對象,當需要壹個新的對象時,python可能會返回已經存在的某個類型和值都壹致的對象的引用。而且這種機制並不會影響 a 和 b 的相互獨立性,因為當兩個元素指向同壹個不可變對象時,對其中壹個賦值不會影響另外壹個。

我們可以用壹個包含可變對象的列表來確切地展示“淺拷貝”與“深拷貝”的區別:

1234567891011121314151617181920

>>> import copy>>> a = [[1, 2],[5, 6], [8, 9]]>>> b = copy.copy(a) # 淺拷貝得到b>>> c = copy.deepcopy(a) # 深拷貝得到c>>> print(id(a), id(b)) # a 和 b 不同139832578518984 139832578335520>>> for x, y in zip(a, b): # a 和 b 的子對象相同... print(id(x), id(y))... 139832578622816 139832578622816139832578622672 139832578622672139832578623104 139832578623104>>> print(id(a), id(c)) # a 和 c 不同139832578518984 139832578622456>>> for x, y in zip(a, c): # a 和 c 的子對象也不同... print(id(x), id(y))... 139832578622816 139832578621520139832578622672 139832578518912139832578623104 139832578623392

從這個例子中可以清晰地看出淺拷貝與深拷貝地區別。

總結:

1、賦值:簡單地拷貝對象的引用,兩個對象的id相同。

2、淺拷貝:創建壹個新的組合對象,這個新對象與原對象***享內存中的子對象。

3、深拷貝:創建壹個新的組合對象,同時遞歸地拷貝所有子對象,新的組合對象與原對象沒有任何關聯。雖然實際上會***享不可變的子對象,但不影響它們的相互獨立性。

淺拷貝和深拷貝的不同僅僅是對組合對象來說,所謂的組合對象就是包含了其它對象的對象,如列表,類實例。而對於數字、字符串以及其它“原子”類型,沒有拷貝壹說,產生的都是原對象的引用。