一、三个概念别混
• 赋值(aliasing):b = a
不拷贝数据,a、b 指向同一个对象。
• 浅拷贝(shallow copy):只复制最外层容器,容器里的元素仍是原来的引用。
常见:copy.copy(x)、x.copy()、list(x)、x[:](列表切片)、dict(x) / set(x)。
• 深拷贝(deep copy):递归复制容器及其所有可达子对象。
常见:copy.deepcopy(x)。
对于不可变对象(int/str/tuple等,且元组内不含可变对象),浅/深拷贝的效果通常一样——因为没必要复制内部内容。
⸻
二、最小示例(看得见的差异)
import copy
a = {"nums": [1, 2], "x": 10}
b = a # 赋值:同一个对象
c = a.copy() # 浅拷贝:只拷贝最外层 dict
d = copy.deepcopy(a) # 深拷贝:递归地全拷
a["nums"].append(3)
a["x"] = 99
print("a:", a) # {'nums': [1, 2, 3], 'x': 99}
print("b:", b) # 跟 a 完全一样(同一对象)
print("c:", c) # 'nums' 跟 a 共享,同步变成 [1,2,3];但 'x' 不会跟着改
print("d:", d) # 完全独立,仍是 {'nums': [1,2], 'x': 10}
要点:浅拷贝后修改“嵌套里的可变对象”(如列表/字典),会影响原对象;深拷贝不会。
⸻
三、常用拷贝方式速查
浅拷贝
• 列表:b = a[:] 或 b = list(a) 或 b = a.copy()
• 字典:b = dict(a) 或 b = a.copy()
• 集合:b = set(a) 或 b = a.copy()
• 通用:import copy; b = copy.copy(a)
深拷贝
• 通用:import copy; b = copy.deepcopy(a)
⸻
四、几个容易踩的坑
1)元组“看起来不可变”,但内部可能是可变的
import copy
t1 = (1, [2, 3])
t2 = copy.copy(t1) # 浅拷贝
t3 = copy.deepcopy(t1) # 深拷贝
t1[1].append(4)
print(t2) # (1, [2, 3, 4]) ← 共享了那只列表
print(t3) # (1, [2, 3]) ← 深拷贝隔离成功
2)自引用/循环引用
deepcopy 使用内部的 memo 字典跟踪已复制对象,可安全处理自引用结构:
import copy
a = []
a.append(a)
b = copy.deepcopy(a) # 不会无限递归
3)外部资源对象通常不适合深拷贝
比如打开的文件句柄、线程锁、数据库连接……
深拷贝它们没有意义,常常会抛错或只做浅拷贝。此类对象应显式重建或在类中自定义拷贝策略。
4)numpy / pandas 的 .copy() 语义跟 Python 标准库不同
• numpy.ndarray.copy() 会复制数据缓冲(更像“深拷贝数据”),但 view 不是拷贝。
• pandas.DataFrame.copy(deep=True) 是数据级拷贝;从 2.0 起引入 Copy-on-Write,行为更复杂。
要分清:库内的 copy ≠ copy 模块的浅/深拷贝 含义完全一致。
⸻
五、自定义类如何控制拷贝?
实现 copy 与 deepcopy(self, memo):
import copy
class Box:
def __init__(self, items):
self.items = items
def __copy__(self):
# 浅拷贝:复制最外层,内部共享
cls = self.__class__
new = cls(self.items) # 不复制 items
return new
def __deepcopy__(self, memo):
cls = self.__class__
new = cls(copy.deepcopy(self.items, memo))
return new
b1 = Box([1,2])
b2 = copy.copy(b1)
b3 = copy.deepcopy(b1)
⸻
六、怎么选?
• 数据一层结构或内部全是不可变 → 浅拷贝即可,快且省内存。
• 有嵌套可变对象且需要完全隔离 → 深拷贝。
• 大对象/性能敏感 → 尽量避免深拷贝;考虑设计为不可变数据或显式构造新对象只复制需要变动的部分。
⸻
七、可直接运行的小测
import copy
def show(title, obj):
print(title, obj, "| id(obj):", id(obj))
a = {"xs": [1,2], "y": {"z": 3}}
b = a # 赋值
c = a.copy() # 浅拷贝
d = copy.deepcopy(a) # 深拷贝
a["xs"].append(9)
a["y"]["z"] = 7
show("a", a) # xs -> [1,2,9], y.z -> 7
show("b", b) # 同 a
show("c", c) # xs 受影响(共享),y.z 也受影响(共享),但 c 本身的 id 不同
show("d", d) # 完全没受影响
⸻
一句话总结:
• 浅拷贝:只复制壳,里头东西共用。
• 深拷贝:把里里外外都复制一份,互不影响。
按数据结构与性能需求选择即可。
1083

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



