1. 程式人生 > >python的深拷貝和淺拷貝

python的深拷貝和淺拷貝

內存區域 需要 不可變 python3 復制 deepcopy 原始的 pen -m

# 對象賦值
a = 'hello world'
b = a
print('a:',a,', b:',b)
# a: hello world , b: hello world
print(id(a)==id(b))
# True
a = 'Hello World'
print('a:',a,', b:',b)
# Hello World , b: hello world
print(id(a)==id(b))
# False


a = 1
b = a
print('a:',a,', b:',b)
# a: 1 , b: 1
print(id(a)==id(b))
# True
a = 2
print('a:',a,', b:',b)
# a: 2 , b: 1
print(id(a)==id(b))
# False


a = ['x','y',[1,2,3]]
b = a
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3]] , b: ['x', 'y', [1, 2, 3]]
print(id(a)==id(b))
# True
a.append('hello')
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3], 'hello'] , b: ['x', 'y', [1, 2, 3], 'hello']
print(id(a)==id(b))
# True
a[2].append(4)
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3], 'hello'] , b: ['x', 'y', [1, 2, 3], 'hello']
print(id(a)==id(b))
# True

"""
所以在python中,對象的賦值都是進行對象引用(內存地址)傳遞,只要a的內存地址沒有變化,a和b的內容都會始終一樣。
"""

a = ['x','y',[1,2,3]]
b = a[:]
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3]] , b: ['x', 'y', [1, 2, 3]]
print(id(a)==id(b))
# False
print([id(i) for i in a])
# [2059734973832, 2059735268016, 2059766662792]
print([id(i) for i in b])
# [2059734973832, 2059735268016, 2059766662792]

a.append('hello')
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3], 'hello'] , b: ['x', 'y', [1, 2, 3]]
print(id(a)==id(b))
# False
a[2].append(4)
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3, 4], 'hello'] , b: ['x', 'y', [1, 2, 3, 4]]
print(id(a)==id(b))
# False

print('淺拷貝')
# 淺拷貝
import copy
a = ['x','y',[1,2,3,[4,5,6]]]
d = copy.copy(a)
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3, [4, 5, 6]]] , b: ['x', 'y', [1, 2, 3, 4]]
print(id(a)==id(b))
# False
print([id(i) for i in a])
# [2640575102344, 2640603314864, 2640606922568]
print([id(i) for i in b])
# [2640575102344, 2640603314864, 2640606922824]
a[2].append(4)
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3, [4, 5, 6], 4]] , b: ['x', 'y', [1, 2, 3, 4]]
tmp_list_a = a[2]
print(id(tmp_list_a))
# 2640606922568
print([id(i) for i in tmp_list_a])
# [1434892752, 1434892784, 1434892816, 2640606922632, 1434892848]
tmp_list_b = b[2]
print(id(tmp_list_b))
# 2640606922824
print([id(i) for i in tmp_list_b])
# [1434892752, 1434892784, 1434892816, 1434892848]

"""
所以在python(python3.6)中淺拷貝會將不可變元素的地址直接拷貝,而可變對象如list會用新的地址指向原list內存區域,相當於兩個不同的指針指向同樣的內存區。
"""

# 深拷貝

import copy
a = ['x','y',[1,2,3,[4,5,6]]]
b = copy.deepcopy(a)
print('a:',a,', b:',b)
# a: ['x', 'y', [1, 2, 3, [4, 5, 6]]] , b: ['x', 'y', [1, 2, 3, [4, 5, 6]]]
print(id(a)==id(b))
# False
print([id(i) for i in a])
# [2460486303112, 2460486597296, 2460490204808]
print([id(i) for i in b])
# [2460486303112, 2460486597296, 2460490204616]
tmp_list_a = a[2]
print(id(tmp_list_a))
# 2460490204808
print([id(i) for i in tmp_list_a])
# [1434892752, 1434892784, 1434892816, 2460490204872]
tmp_list_b = b[2]
print(id(tmp_list_b))
# 2460490204616
print([id(i) for i in tmp_list_b])
# [1434892752, 1434892784, 1434892816, 2460490204552]

"""
深拷貝,就是會遞歸的進行拷貝,直到查找到原子類型。
"""

# 補充:
"""
對於拷貝有一些特殊情況:
    對於非容器類型(如數字、字符串、和其他'原子'類型的對象)沒有拷貝這一說
也就是說,對於這些類型,如果元祖變量只包含原子類型對象,則不能深拷貝。
 如下例子:
"""
a = (1,'x')
b = copy.copy(a)
print(id(a)==id(b))   #沒有拷貝
# True
b = copy.deepcopy(a)
print(id(a)==id(b))   #沒有拷貝
# True

a = (1,'x',[2])
b = copy.copy(a)
print(id(a)==id(b))   #沒有拷貝
# True
b = copy.deepcopy(a)
print(id(a)==id(b))   #拷貝
# False

# 總結
"""
* Python中對象的賦值都是進行對象引用(內存地址)傳遞
* 使用copy.copy(),可以進行對象的淺拷貝,它復制了對象,但對於對象中的元素,依然使用原始的引用.
* 如果需要復制一個容器對象,以及它裏面的所有元素(包含元素的子元素),可以使用copy.deepcopy()進行深拷貝
* 對於非容器類型(如數字、字符串、和其他'原子'類型的對象)沒有被拷貝一說
* 如果元祖變量只包含原子類型對象,則不能深拷貝
"""

python的深拷貝和淺拷貝