新浪博客

Pythoncopy模块--深copy和浅copy

2024-03-20 18:01阅读:
作者: Sam(甄峰) sam_code@hotmail.com


0.基础:
可变对象不可变对象
在前面讨论可变对象不可变对象时,有变量(Variables)和对象(Objects)两个概念。
对象(Objects)指内存中存储数据的实体。包括三个要素: 地址,类型,值。Python中所有实体都是对象。
变量(Variables)则是对象的引用或者说别名。实质上是对象的地址。
例1: 对象有类型,变量无类型:
val_test = 1234
print('val_test:', val_test, 'type:', type(val_test), 'id:', id(val_test))
val_test = '1234'
print('New val_test:', val_test, 'type:', type(val_test), 'id:', id(val_test))


val_test: 1234 type: id: 1739458650128
New val_test: 1234 type: id: 1737314300464
可以看到,变量的类型随它指向的对象
的类型而变化。变量的 赋值 (Assignment)只是改变了变量所指向的对象。对不可变对象赋值 (Assignment)只是创建了新的不可变对象,同时改变了变量的对象引用。

在开发中,我们常需要copy一块数据,在保留原先数据的情况下,修改新的数据。那使用赋值 (Assignment)是无法做到的。因为这样只创建了一个新的变量,而指向同一个对象。于是Python就有了copy模块。


例2: 可变对象的赋值 (Assignment),只是建立了新的变量,而指向同一个object.
list_Name = ['Alchile', 'Alicia', 'Grace', 'Claire']
list_N = list_Name
print('list_Name:', list_Name, 'type:', type(list_Name), 'id:', id(list_Name))
print('list_N:', list_N, 'type:', type(list_N), 'id:', id(list_N))
list_Name[0] = 'Achilles'
print('New list_Name:', list_Name, 'type:', type(list_Name), 'id:', id(list_Name))
print('New list_N:', list_N, 'type:', type(list_N), 'id:', id(list_N))

list_Name: ['Alchile', 'Alicia', 'Grace', 'Claire'] type: id: 2260021037312
list_N: ['Alchile', 'Alicia', 'Grace', 'Claire'] type: id: 2260021037312
New list_Name: ['Achilles', 'Alicia', 'Grace', 'Claire'] type: id: 2260021037312
New list_N: ['Achilles', 'Alicia', 'Grace', 'Claire'] type: id: 2260021037312



可以看到,不管可变对象还是不可变对象赋值 (Assignment),只是建立了新的变量,而指向同一个object.




1. 浅拷贝copy和深拷贝deepcopy:
1.1:不可变对象:
对于不可变对象,无论深、浅拷贝,内存地址 (id) 都是一成不变。
#不可变对象的浅copy和深copy
iVal_test1 = 1234
sVal_test1 = 'Hello World!'
iVal_copy = copy.copy(iVal_test1)
sVal_copy = copy.copy(sVal_test1)
iVal_dcopy = copy.deepcopy(iVal_test1)
sVal_dcopy = copy.deepcopy(sVal_test1)

print('iVal_test1:', iVal_test1, 'type:', type(iVal_test1), 'id:', id(iVal_test1))
print('iVal_copy:', iVal_copy, 'type:', type(iVal_copy), 'id:', id(iVal_copy))
print('iVal_dcopy:', iVal_dcopy, 'type:', type(iVal_dcopy), 'id:', id(iVal_dcopy))
print('sVal_test1:', sVal_test1, 'type:', type(sVal_test1), 'id:', id(sVal_test1))
print('sVal_copy:', sVal_copy, 'type:', type(sVal_copy), 'id:', id(sVal_copy))
print('sVal_dcopy:', sVal_dcopy, 'type:', type(sVal_dcopy), 'id:', id(sVal_dcopy))


iVal_test1: 1234 type: id: 2812703514640
iVal_copy: 1234 type: id: 2812703514640
iVal_dcopy: 1234 type: id: 2812703514640
sVal_test1: Hello World! type: id: 2812710449584
sVal_copy: Hello World! type: id: 2812710449584
sVal_dcopy: Hello World! type: id: 2812710449584


可以看到,对不可变对象,浅拷贝 copy和深拷贝 deepcopy和赋值 (Assignment)一样,都是把新变量指向同一份对象。


1.2:可变对象:
如例2所示。 可变对象的赋值 (Assignment),只是建立了新的变量,而指向同一个object. 所以着重看看浅拷贝深拷贝

1.2.1: 可变对象的浅拷贝:
使用copy.copy()函数,会把可变对象如List重新创建一个新的对象。 但这个对象只创建了最外层,包含的内层对象则并未创建,而是又引用了之前的object. 描述的不够清楚。仔细看代码。尤其id.
#可变对象的浅copy
list_test = [1, 2, 3, [11, 22, 33]]
list_copy = copy.copy(list_test)
print('list_test:', list_test, 'type:', type(list_test), 'id:', id(list_test), 'index 3 id:', id(list_test[3]))
print('list_copy:', list_copy, 'type:', type(list_copy), 'id:', id(list_copy), 'index 3 id:', id(list_copy[3]))
list_test.append(4)
list_copy[0] = 5
list_test[3].append(44)
list_copy[3][0] = 555
print('list_test:', list_test, 'type:', type(list_test), 'id:', id(list_test), 'index 3 id:', id(list_test[3]))
print('list_copy:', list_copy, 'type:', type(list_copy), 'id:', id(list_copy), 'index 3 id:', id(list_copy[3]))


list_test: [1, 2, 3, [11, 22, 33]] type: id: 1844139425472 index 3 id: 1844412449088
list_copy: [1, 2, 3, [11, 22, 33]] type: id: 1844139423872 index 3 id: 1844412449088
list_test: [1, 2, 3, [555, 22, 33, 44], 4] type: id: 1844139425472 index 3 id: 1844412449088
list_copy: [5, 2, 3, [555, 22, 33, 44]] type: id: 1844139423872 index 3 id: 1844412449088


可以看到:最外层List确实重新创建的Object,因为ID都不同了。所以对外层中元素进行增加,删除,修改,两个Object中互不影响。
但内层List,他们的ID是相同的。所以增加删除修改在其中一个上时,另一个也会修改。


1.2.2:可变对象的深拷贝:
拷贝可变对象如 list 的“外围+内层”而非引用
#可变对象的深copy
list_test = [1, 2, 3, [11, 22, 33]]
list_copy = copy.deepcopy(list_test)
print('list_test:', list_test, 'type:', type(list_test), 'id:', id(list_test), 'index 3 id:', id(list_test[3]))
print('list_copy:', list_copy, 'type:', type(list_copy), 'id:', id(list_copy), 'index 3 id:', id(list_copy[3]))
list_test.append(4)
list_copy[0] = 5
list_test[3].append(44)
list_copy[3][0] = 555
print('list_test:', list_test, 'type:', type(list_test), 'id:', id(list_test), 'index 3 id:', id(list_test[3]))
print('list_copy:', list_copy, 'type:', type(list_copy), 'id:', id(list_copy), 'index 3 id:', id(list_copy[3]))


list_test: [1, 2, 3, [11, 22, 33]] type: id: 2614801039104 index 3 id: 2615073850816
list_copy: [1, 2, 3, [11, 22, 33]] type: id: 2614801037504 index 3 id: 2615074563008
list_test: [1, 2, 3, [11, 22, 33, 44], 4] type: id: 2614801039104 index 3 id: 2615073850816
list_copy: [5, 2, 3, [555, 22, 33]] type: id: 2614801037504 index 3 id: 2615074563008


内层和外层均重新创建object,所以修改任意一个,另一个不受影响。






我的更多文章

下载客户端阅读体验更佳

APP专享