作者: 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,所以修改任意一个,另一个不受影响。
Pythoncopy模块--深copy和浅copy
作者: 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,所以修改任意一个,另一个不受影响。