深拷贝浅拷贝

不可变对象:该对象所指向的内存中的值不能被改变,修改对象的值时,由于其指向的值不能被改变,因此实际上是在内存中重新开辟一个地址用来存储新的值,然后将对象指向这个新值。本质上是两个对象,赋值前后对象id发生了变化。python中的不可变对象包括:bool、int、str、float、tuple、frozenset、None。

可变对象:该对象所指向的内存中的值可以被改变。变量(引用)的值发生改变时,实际上是其指向的值直接发生改变,没有开辟新的内存地址。python中的可变对象包括:list、dict、set

浅拷贝:通常指构造一个新的集合对象,然后用原始对象中的找到的子对象的引用来填充它。浅层的复制只有一层深度,复制过程中不会递归,所以不会创建子对象本身的副本。

案例1

import copy
lst = [[1,2],3,4]
new3_lst = copy.copy(lst)
print(id(lst), lst)  # 2027983558024 [[1, 2], 3, 4]
print(id(new3_lst), new3_lst)  # 2027983557000 [[1, 2], 3, 4]
==>先打印一下刚复制出来的两个对象及内存编号
print('-------------------')
new3_lst[0][0] = 4
print(id(lst),lst)   # 2027983558024 [[4, 2], 3, 4]
print(id(new3_lst),new3_lst)  # 2027983557000 [[4, 2], 3, 4]
==>推出:改变拷贝对象的子对象的成员值,会同时影响原始对象和拷贝对象
print('-------------------')
new3_lst[2] = 0
print(id(lst),lst)  # 2757271180296 [[4, 2], 3, 4]
print(id(new3_lst),new3_lst)  # 2757271135560 [[4, 2], 3, 0]
==>推出:改变拷贝对象的第一层次的成员值,不会影响原始对象

print('-------------------')
lst[2] = 0
print(id(lst),lst)  # 2757271180296 [[4, 2], 3, 0]
print(id(new3_lst),new3_lst)  # 2757271135560 [[4, 2], 3, 0]
print('-------------------')
lst[0][0] = 9
print(id(lst),lst)  # 2757271180296 [[9, 2], 3, 0]
print(id(new3_lst),new3_lst)  # 2757271135560 [[9, 2], 3, 0]
==>推出:改变原始对象的成员或者子对象的成员值,拷贝对象的元素跟着改变
"""
总结
浅拷贝,改变原始对象的成员或者子对象的成员值,拷贝对象的元素跟着改变
       改变拷贝对象的子对象的成员值,会同时影响原始对象和拷贝对象
       改变拷贝对象的第一层次的成员值,不会影响原始对象
"""

案例2

# example 1
lst = [[1,2],3,4]
new2_lst = list(lst)
print(id(lst))  # 2291852075656
print(id(new2_lst))  # 2291852075656
print('-------------------')
new2_lst[0][0] = 40
print(id(lst),lst)   # 2364733153992 [[40, 2], 3, 4]
print(id(new2_lst),new2_lst)  # 2364736713480 [[40, 2], 3, 4]
print('-------------------')
new2_lst[2] = 40
print(id(lst),lst)  # 2364733153992 [[40, 2], 3, 4]
print(id(new2_lst),new2_lst)  # 2364736713480 [[40, 2], 3, 40]

print('***********************')
lst[0][1] = 20
print(id(lst),lst)  # 2364733153992 [[40, 20], 3, 4]
print(id(new2_lst),new2_lst)  # 2364736713480 [[40, 20], 3, 40]
print('-------------------')
lst[2] = 30
print(id(lst),lst)  # 2364733153992 [[40, 20], 3, 30]
print(id(new2_lst),new2_lst)  # 2364736713480 [[40, 20], 3, 40]
"""
总结
修改第一层次的成员值,不会影响拷贝对象;修改子对象的成员值(第二层次),会同时影响原始对象和拷贝对象
"""

深拷贝:深拷贝使复制过程递归,即首先构造一个新的集合对象,然后递归地用在原始对象中找到的子对象的副本来填充它。通过深拷贝复制对象,是原始对象及其所有子对象的完全独立的克隆。

# 深拷贝: 拷贝对象及子对象(递归)
lst1 = [[1,2],3,4]
print('--------深拷贝--------')
import copy
new4_lst = copy.deepcopy(lst1)
print(id(lst1),lst1)  # 1951550628552 [[1, 2], 3, 4]
print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 2], 3, 4]
==>先打印一下刚深拷贝出来的两个对象及内存编号
print('-------------------')
# 改变新对象的子对象的成员值,不会影响原始对象
new4_lst[0][1] = 9
print(id(lst1),lst1)  # 1951550628552 [[1, 2], 3, 4]
print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 9], 3, 4]

print('-------------------')
# 改变拷贝对象的第一层次的成员值,不会影响原始对象
new4_lst[1] = 10
print(id(lst1),lst1)  # 1951550628552 [[1, 2], 3, 4]
print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 9], 10, 4]

print('-------------------')
# 改变原始对象的子对象的成员值,不会影响拷贝对象
lst1[0][1] = 20
print(id(lst1),lst1)  # 1951550628552 [[1, 20], 3, 4]
print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 9], 10, 4]

print('-------------------')
# 改变原始对象的第一层次的成员值,不会影响拷贝对象
lst1[1] = 16
print(id(lst1),lst1)   # 1951550628552 [[1, 20], 16, 4]
print(id(new4_lst),new4_lst)  # 1951582564552 [[1, 9], 10, 4]

"""
总结
深拷贝,新旧对像及其子对象的成员值完全独立,互不影响
"""

总结

  • 不可变对象没有深拷贝和浅拷贝之分,可以理解为都是深拷贝
  • 创建对象的浅拷贝不会克隆子对象,不能完全对立与原始对象
  • 深拷贝会递归克隆原始对象,两者完全独立,互不影响,创建深拷贝的速度较慢
posted @ 2020-07-14 00:19  我是一言  阅读(64)  评论(0编辑  收藏  举报