Pythoncopy模块--深copy和浅copy

2024-03-20 18:01:03
标签: python

作者: 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,所以修改任意一个,另一个不受影响。

 

 




 

 

阅读(0) 收藏(0) 转载(0) 举报/Report
相关阅读

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有