Python深浅拷贝
文章目录
- 1 概述
- 2 数据类型
- 2.1 可变类型
- 2.2 不可变类型
- 3 深浅拷贝
- 3.1 浅拷贝
- 3.2 深拷贝
- 4 深浅拷贝对数据类型的影响
- 4.1 对于不可变类型的影响
- 4.2 对于可变类型的影响
- 4.3 总结
- 5 实现机制
- 5.1 copy
- 5.2 id
- 6 示例
- 6.1 普通赋值
- 6.2 浅拷贝可变类型
- 6.3 浅拷贝不可变类型
- 6.4 深拷贝可变类型
- 6.5 深拷贝不可变类型
- 7 注意事项
1 概述
在 Python 中,可变类型和不可变类型的拷贝行为有所不同。理解它们的区别对于正确使用浅拷贝和深拷贝非常重要。
2 数据类型
在Python中,从对象的内存值是否可以被修改
的角度来考虑,数据类型可分为可变类型和不可变类型。
2.1 可变类型
可变类型的对象在创建后,其内存中的值可以被修改,而对象的内存地址(引用)不变。常见类型包括列表(list)
、字典(dict)
、集合 (set)
。
2.2 不可变类型
对象一旦创建,其内存中的值就不能被修改。如果需要“修改”不可变对象,实际上是创建了一个新对象,并将变量(引用)指向新对象的内存地址。常见类型包括字符串 (str)
、元组 (tuple)
、数值类型(整型 int、浮点型 float)
、布尔类型 (bool)
。
3 深浅拷贝
在 Python 中,从对象及其嵌套对象的复制方式
的角度来考虑,拷贝可分为浅拷贝和深拷贝。
3.1 浅拷贝
浅拷贝只复制对象本身,而不复制对象内部的嵌套对象。浅拷贝后的对象和原对象共享内部的嵌套对象。
3.2 深拷贝
深拷贝会递归复制对象及其所有嵌套对象。深拷贝后的对象和原对象完全独立,互不影响。
4 深浅拷贝对数据类型的影响
4.1 对于不可变类型的影响
对于不可变类型(如字符串 (str)
、元组 (tuple)
、数值类型(整型 int、浮点型 float)
等),无论是浅拷贝还是深拷贝,都不会创建新对象,而是直接引用原对象。这是因为不可变对象的值不能被修改,共享是安全的。
4.2 对于可变类型的影响
对于对于可变类型(如列表、字典、集合等),深浅拷贝的行为会有所不同:
浅拷贝:创建一个新对象,但嵌套的可变对象仍然是共享的。
深拷贝:创建一个新对象,并递归复制所有嵌套的可变对象。
4.3 总结
类型 | 浅拷贝行为 | 深拷贝行为 |
---|---|---|
不可变类型 | 与赋值相同,直接引用原对象(如果包含可变对象,则嵌套的可变对象共享) | 与赋值相同,直接引用原对象(如果包含可变对象,则嵌套的可变对象共享) |
可变类型 | 创建新对象,但嵌套的可变对象共享 | 创建新对象,并递归复制所有嵌套的可变对象 |
5 实现机制
5.1 copy
在 Python 中,浅拷贝和深拷贝是通过copy
模块中的copy()
和deepcopy()
函数实现的。
浅拷贝:
copy模块的copy()
深拷贝:
copy模块的deepcopy()函数
5.2 id
在 Python 中,可以通过id()
函数获取对象的内存地址。id()
返回一个整数,表示对象的唯一标识符(通常是对象在内存中的地址)。这个地址在对象的生命周期内是唯一的,可以用来判断两个变量是否指向同一个对象。
6 示例
6.1 普通赋值
普通赋值,内存地址都一样
# 不可变类型
num_1 = 8919
num_2 = num_1
print(f'id(num_1):{id(num_1)}') # 2522975289840
print(f'id(num_2):{id(num_2)}') # 2522975289840
print(f'id(8919):{id(8919)}') # 2522975289840
# 可变类型
list_1 = ['辰南', '梦可儿', '龙舞']
list_2 = ['唤魔经', '太上忘情录', '通天动地魔功']
list_3 = [list_1, list_2]
list_4 = list_3
print(f'id(list_3):{id(list_3)}') # 2522975191232
print(f'id(list_4):{id(list_4)}') # 2522975191232
6.2 浅拷贝可变类型
浅拷贝只复制对象本身,而不复制对象内部的嵌套对象
import copy
list_1 = ['辰南', '梦可儿', '龙舞']
list_2 = ['唤魔经', '太上忘情录', '通天动地魔功']
list_3 = [list_1, list_2, 8919, 12]
# 浅拷贝
list_4 = copy.copy(list_3)
print(f'id(list_3):{id(list_3)}') # 对象本身地址不一样:1579186077888
print(f'id(list_4):{id(list_4)}') # 对象本身地址不一样:1579183616704
print(id(list_2)) # 嵌套对象地址共享:1579183315072
print(id(list_3[1])) # 嵌套对象地址共享:1579183315072
list_2[2] = '逆乱八式' # 嵌套对象内容修改,引用对象内容同时发生改变
print(f'list_3:{list_3}') # list_3:[['辰南', '梦可儿', '龙舞'], ['唤魔经', '太上忘情录', '逆乱八式'], 8919, 12]
print(f'list_4:{list_4}') # list_4:[['辰南', '梦可儿', '龙舞'], ['唤魔经', '太上忘情录', '逆乱八式'], 8919, 12]
6.3 浅拷贝不可变类型
与赋值相同,直接引用原对象(如果包含可变对象,则嵌套的可变对象共享)
import copy
tuple_1 = ('辰南', '梦可儿', '龙舞')
tuple_2 = ('唤魔经', '太上忘情录', '通天动地魔功')
tuple_3 = (tuple_1, tuple_2, 8919, 12)
tuple_4 = copy.copy(tuple_3)
print(f'id(list_3):{id(tuple_3)}') # 地址不发生改变:1922101059136
print(f'id(list_4):{id(tuple_4)}') # 地址不发生改变:1922101059136
print(f'id(tuple_2):{id(tuple_2)}') # 共享地址:2341031630272
print(f'id(tuple_3[1]):{id(tuple_3[1])}') # 共享地址:2341031630272
6.4 深拷贝可变类型
深拷贝会递归复制对象及其所有嵌套对象。深拷贝后的对象和原对象完全独立,互不影响。
import copy
list_1 = ['辰南', '梦可儿', '龙舞']
list_2 = ['唤魔经', '太上忘情录', '通天动地魔功']
list_3 = [list_1, list_2, 8919, 12]
# 浅拷贝
list_4 = copy.deepcopy(list_3)
print(f'id(list_3):{id(list_3)}') # 对象本身地址不一样:2252152333504
print(f'id(list_4):{id(list_4)}') # 对象本身地址不一样:2252171929023
print(id(list_2)) # 嵌套对象地址共享:2252175821184
print(id(list_3[1])) # 嵌套对象地址共享:2252175821184
list_1[2] = '李若兰' # 对深拷贝对象不影响
list_2[2] = '逆乱八式' # 对深拷贝对象不影响
print(f'list_3:{list_3}') # [['辰南', '梦可儿', '李若兰'], ['唤魔经', '太上忘情录', '逆乱八式'], 8919, 12]
print(f'list_4:{list_4}') # [['辰南', '梦可儿', '龙舞'], ['唤魔经', '太上忘情录', '通天动地魔功'], 8919, 12]
6.5 深拷贝不可变类型
与赋值相同,直接引用原对象(如果包含可变对象,则嵌套的可变对象共享)
import copy
tuple_1 = ('辰南', '梦可儿', '龙舞')
tuple_2 = ('唤魔经', '太上忘情录', '通天动地魔功')
tuple_3 = (tuple_1, tuple_2, 8919, 12)
tuple_4 = copy.deepcopy(tuple_3) # 深拷贝
print(f'id(list_3):{id(tuple_3)}') # 地址不发生改变:2321897201216
print(f'id(list_4):{id(tuple_4)}') # 地址不发生改变:2321897201216
print(f'id(tuple_2):{id(tuple_2)}') # 共享地址:2321937124417
print(f'id(tuple_3[1]):{id(tuple_3[1])}') # 共享地址:2321937124417
7 注意事项
- 对于不可变类型,深浅拷贝的效果与赋值相同,因为不可变对象的值不能被修改。
- 如果不可变对象包含可变对象(如元组中包含列表),则需要注意嵌套对象的共享问题。
- 深拷贝可能会比较耗时,尤其是当对象嵌套层级很深或数据量很大时。