python中copy和deepcopy区别

核心区别一句话概括:

  • copy (浅拷贝):只复制对象本身,而不复制对象内部所引用的子对象。新旧对象共享内部的子对象。

  • deepcopy (深拷贝):复制对象本身以及它内部所有层次引用的子对象,直到最底层。新旧对象完全独立,互不影响。


为了更好地理解,我们通常将数据分为两种类型:

  1. 不可变对象:数字、字符串、元组等。对于这些类型,copy 和 deepcopy 的效果几乎没有区别,因为一旦创建就不能修改,复制时可能会直接引用同一个对象。

  2. 可变对象:列表、字典、集合等。copy 和 deepcopy 的区别在它们身上表现得淋漓尽致。


详细解释和示例

1. 赋值(Assignment)

首先,要理解“赋值”根本不是拷贝,它只是给现有对象起了一个新名字(绑定了一个新标签)。

original = [1, 2, [3, 4]]
assigned = original  # 这只是赋值,不是拷贝

# 修改原列表
original.append(5)
print(original)  # 输出: [1, 2, [3, 4], 5]
print(assigned)  # 输出: [1, 2, [3, 4], 5] (assigned 也跟着变了)

# 修改原列表中的子列表
original[2].append(99)
print(original)  # 输出: [1, 2, [3, 4, 99], 5]
print(assigned)  # 输出: [1, 2, [3, 4, 99], 5] (assigned 也跟着变了)

original 和 assigned 指向内存中的同一个列表对象,所以一个的任何改变都会反映到另一个上。


2. 浅拷贝 (copy)

使用 copy模块 的 copy() 函数或可变对象自带的 .copy() 方法。

import copy

original = [1, 2, [3, 4]]
shallow_copied = copy.copy(original)  # 创建了一个新的列表对象

# 1. 修改原列表的第一层(添加新元素)
original.append(5)
print(original)      # 输出: [1, 2, [3, 4], 5]
print(shallow_copied) # 输出: [1, 2, [3, 4]] (新列表没有受到影响)

# 2. 修改原列表中不可变元素
original[0] = 100
print(original)      # 输出: [100, 2, [3, 4], 5]
print(shallow_copied) # 输出: [1, 2, [3, 4]] (新列表没有受到影响)

# 3. 修改原列表中的子对象(可变对象)
original[2].append(99) # 修改双方共享的子列表
print(original)      # 输出: [100, 2, [3, 4, 99], 5]
print(shallow_copied) # 输出: [1, 2, [3, 4, 99]] (新列表的子列表也被改变了!)

图解浅拷贝:

original  ->  [ 1, 2, ● ] 
                     ↓
                     [3, 4]
                     ↑
shallow_copied -> [ 1, 2, ● ]

可以看到,original 和 shallow_copied 是两个不同的列表,但它们内部的第三个元素(指向子列表的引用)是同一个。所以修改这个共享的子列表,两个“父列表”都会看到变化。


3. 深拷贝 (deepcopy)
import copy

original = [1, 2, [3, 4]]
deep_copied = copy.deepcopy(original) # 创建了一个全新的、完全独立的对象树

# 1. 修改原列表的第一层
original.append(5)
print(original)     # 输出: [1, 2, [3, 4], 5]
print(deep_copied)  # 输出: [1, 2, [3, 4]] (完全不受影响)

# 2. 修改原列表中的子对象
original[2].append(99)
print(original)     # 输出: [1, 2, [3, 4, 99], 5]
print(deep_copied)  # 输出: [1, 2, [3, 4]] (完全不受影响!子列表也是独立的)

图解深拷贝:

original  ->  [ 1, 2, ● ] 
                     ↓
                     [3, 4]

deep_copied -> [ 1, 2, ● ]
                     ↓
                     [3, 4] (这是一个全新的副本)

original 和 deep_copied 以及它们内部的所有可变子对象都是完全独立的,不存在任何共享关系。修改任何一个都不会影响另一个。


总结对比表

特性赋值 (=)浅拷贝 (copy.copy())深拷贝 (copy.deepcopy())
拷贝内容只创建引用拷贝父对象,不拷贝内部子对象拷贝父对象及其所有子对象
内存地址完全相同父对象地址不同,子对象地址相同父对象和子对象地址都不同
修改原对象的一层影响新对象不影响新对象不影响新对象
修改原对象的子对象影响新对象影响新对象不影响新对象
性能与内存开销最小开销中等开销最大(递归拷贝所有层级)
使用场景需要完全联动的别名对象结构简单,或子对象不可变,或需要共享子对象对象结构复杂,需要完全独立的副本

如何选择?

  • 如果你的对象内部只有不可变对象(如列表里全是数字或字符串),用 copy 和 deepcopy 效果几乎一样,但 copy 更快。

  • 如果你的对象内部包含其他可变对象(如列表嵌套列表、字典嵌套列表),并且你希望新旧对象完全独立,互不干扰,就必须使用 deepcopy

  • 如果你希望不介意新旧对象共享内部的可变子对象,可以使用 copy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值