一、基本概念
在Python中,赋值(=)只是让新变量指向同一个对象,并不会创建副本。而拷贝则分为浅拷贝和深拷贝,它们决定了副本与原对象之间的独立程度。
- 可变对象:列表list、字典dict、集合set(值可以修改,修改后内存地址不变)
- 不可变对象:数字int/float、字符串str、元组tuple(值不能修改,修改会生成新对象)
二、相同点和不同点
在Python中,浅拷贝(Shallow Copy) 和 深拷贝(Deep Copy) 核心区别是:拷贝后生成的新对象,是否会递归复制嵌套的子对象。
相同点:
1、如果是不可变对象,如:字符串、元组。深拷贝和浅拷贝对原拷贝对象都不会有影响
2、如果是可变对象,且不带子对象,如:列表、字典。深拷贝和浅拷贝对原拷贝对象都不会有影响
3、如果是可变对象,且带子对象,修改不是子对象的内容。深拷贝和浅拷贝对原拷贝对象都不会有影响
不同点:
如果是可变对象,且带子对象,修改子对象的内容。深拷贝不会对原拷贝对象有影响,浅拷贝会修改原拷贝对象内容
三、浅拷贝(Shallow Copy)
创建一个新的对象,但新对象中存储的是原对象中元素的引用(即内存地址)。
如果原对象内部还嵌套了其他可变对象,不会递归拷贝嵌套的子对象,新对象和原对象会共享这些内部对象(子对象共用同一个内存地址)。
常见创建方式:
- 列表:list.copy()、copy[:]、list(list_original)
- 字典:dict.copy()
- 通用:copy.copy(x)
特点:
- 顶层对象是独立的,修改顶层元素不影响原对象。
- 修改嵌套的可变对象(如列表中的列表)会影响原对象,因为引用相同(共用内存,修改会互相影响)
3.1、拷贝对象是可变对象,没有子对象
import copy
"""
浅拷贝:
只拷贝容器本身,容器中的元素并未拷贝
第一种:
拷贝对象是可变对象,但没有复杂子对象
结论:
原来的值改变,不会影响浅复制后的值
"""
a = [1, 2, 3, 4, 5]
b = copy.copy(a)
b.append(6)
print("【浅拷贝】===可变对象,且不带子对象===改变拷贝后的对象", b) # [1, 2, 3, 4, 5, 6]
print("【浅拷贝】===可变对象,且不带子对象===原对象", a) # [1, 2, 3, 4, 5]
print("【结论】: 不带复杂子对象的可变对象【浅拷贝】后的对象修改和原对象没有关系\n")
3.2、拷贝对象是可变对象,有子对象
"""
第二种:
拷贝对象是可变对象,且拷贝对象中含有复杂子对象
① 修改拷贝对象中非复杂子对象的内容
② 修改拷贝对象中复杂子对象的内容
结论:
① 修改拷贝对象中非复杂子对象的内容,不管修改拷贝前还是拷贝后的对象,都不会影响互相影响
② 修改拷贝对象中复杂子对象的内容,同时会修改原来拷贝对象中复杂子对象的值
"""
c = [1, 2, [3, 4, 5]]
d = copy.copy(c)
# 1.修改拷贝对象中不是复杂子对象的内容
d[0] = 2
print("【浅拷贝】===》可变对象===》且带复杂子对象===》修改不是子对象的内容", d) # [2, 2, [3, 4, 5]]
print("【浅拷贝】===》可变对象===》且带复杂子对象===》原对象", c) # [1, 2, [3, 4, 5]]
print("【结论】: 带复杂子对象的可变对象【浅拷贝】后【修改非子对象】的内容和原对象没有关系\n")
# 2.修改拷贝对象中复杂子对象的内容
k = copy.copy(c)
k[2][0] = 5
print("【浅拷贝】===》可变对象===》且带复杂子对象===》修改子对象的内容", k) # [1, 2, [5, 4, 5]]
print("【浅拷贝】===》可变对象===》且带复杂子对象===》原对象", c) # [1, 2, [5, 4, 5]]
print("【结论】: 带复杂子对象的可变对象【浅拷贝】后【修改子对象】的内容和原对象有关系=====》浅拷贝修改复杂子对象内容,会影响原对象\n")
四、深拷贝(Deep Copy)
创建一个新的对象,并且递归地拷贝原对象内部所有的子对象,得到完全独立的新副本。新对象与原对象没有任何共享,修改任意一方都不会影响另一方
4.1、拷贝对象是可变对象,没有子对象
"""
第一种:拷贝对象是可变对象,但没有复杂子对象
结论:
原来的值改变,不会影响浅复制后的值
"""
# 1.拷贝对象是可变对象
info = [1, 2, 3, 4, 5]
info_copy = copy.deepcopy(info)
info_copy[4] = 88
print("【深拷贝】===》可变对象===》且不带子对象===》改变拷贝后的对象", info_copy) # [1, 2, 3, 4, 88]
print("【深拷贝】===》可变对象===》且不带子对象===》原对象", info) # [1, 2, 3, 4, 5]
print("【结论】: 不带复杂子对象的可变对象【深拷贝】后的对象修改和原对象没有关系\n")
4.2、拷贝对象是可变对象,有子对象
"""
第二种:拷贝对象是可变对象,拷贝对象中有复杂子对象
① 修改不是复杂子对象的内容
② 修改复杂子对象的内容
结论:
是否有复杂子对象,深拷贝都无影响
"""
# 1.拷贝对象中含有复杂子对象。修改不是子对象的部分
e = {"name": "zkc", "age": 18, "info": [1, 2, 3, 4, 5]}
f = copy.deepcopy(e)
param = {"age": 20}
f.update(param)
print("【深拷贝】===》可变对象===》且不带子对象===》改变拷贝后的对象", f) # {'name': 'zkc', 'age': 20, 'info': [1, 2, 3, 4, 5]}
print("【深拷贝】===》可变对象===》且不带子对象===》原对象", e) # {'name': 'zkc', 'age': 18, 'info': [1, 2, 3, 4, 5]}
print("【结论】: 带复杂子对象的可变对象【深拷贝】后【修改非子对象】的内容和原对象没有关系\n")
# 2.拷贝对象中含有复杂子对象。修改子对象的部分
h = copy.deepcopy(e)
h["info"][0] = 77
print("【深拷贝】===》可变对象===》且带子对象===》改变拷贝后的对象", h) # {'name': 'zkc', 'age': 18, 'info': [77, 2, 3, 4, 5]}
print("【深拷贝】===》可变对象===》且带子对象===》原对象", e) # {'name': 'zkc', 'age': 18, 'info': [1, 2, 3, 4, 5]}
print("【结论】: 带复杂子对象的可变对象【深拷贝】后【修改子对象】的内容和原对象没有关系\n")
五、不可变对象的拷贝
5.1、拷贝对象不可变对象,没有子对象
浅拷贝/深拷贝都不会创建新对象,直接返回原对象引用(效率优化)
如果对象中只包含不可变类型(整数、字符串、元组等),浅拷贝和深拷贝效果看起来一样(因为不可变对象无法被修改,共享无害)。但浅拷贝仍然只拷贝引用,深拷贝也不会复制这些不可变对象本身(Python 内部会复用)
a = (1, 2, 3, 4, 5)
b = copy.copy(a)
c = copy.deepcopy(a)
print(id(a), id(b), id(c))
print(id(a) == id(b) == id(c))
5.2、拷贝对象不可变对象,有子对象
- 浅拷贝:仍返回原对象引用
- 深拷贝:会创建新对象(递归拷贝可变子对象)
# 浅拷贝
d = (1, 2, 3, [5, 6]) # 元组嵌套列表
f = copy.copy(d)
print(id(d) == id(f)) # True 浅拷贝不变
f[3].append(8)
print("【浅拷贝】===》不可变对象===》且带子对象===》原对象",d) # (1, 2, 3, [5, 6, 8])
print("【浅拷贝】===》不可变对象===》且带子对象===》改变拷贝后的对象", f) # (1, 2, 3, [5, 6, 8])
# 深拷贝
a = (1, 2, [3,4]) # 元组嵌套列表
c = copy.deepcopy(a)
c[2].append(5)
print(id(a) == id(c)) # False 深拷贝创建新对象
print("【深拷贝】===》不可变对象===》且带子对象===》原对象",a) # (1, 2, [3, 4])
print("【深拷贝】===》不可变对象===》且带子对象===》改变拷贝后的对象", c) # (1, 2, [3, 4, 5])
六、自定义类的拷贝控制
class MyClass:
def __init__(self, values):
self.values = values
def __copy__(self):
# 自定义浅拷贝
new = MyClass(self.values[:]) # 只拷贝一层
return new
def __deepcopy__(self, memo):
# 自定义深拷贝
new = MyClass(copy.deepcopy(self.values, memo))
return new
1万+

被折叠的 条评论
为什么被折叠?



