Python字典的浅拷贝与深拷贝
Created:
Updated:
前言
在前一篇讲到的是内存空间的引用,而这个知识点跟字典的拷贝息息相关,所以顺便讲下
字典的拷贝同样遵循数据类型的规则,是采用引用,还是新建立对象 而这其中涉及的差别也就是人们常说的深拷贝与浅拷贝
方法
赋值
赋值的话,我们以为我们创建的是新的副本,实则不是
赋值操作创建了对象的一个新的引用。
当你对一个变量进行赋值操作时,你创建了对已存在对象的一个新的引用,而不是创建了一个新的对象。
示例
a = {"key1": [1, 2, 3], "key2": {"nested": 42}, "key3": "123"}
# 将a的值赋值给b
b = a
# 修改key3的值
a["key3"] = "456"
print(a) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '456'}
print(b) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '456'}
# 修改key1的值
a["key1"].append(4)
print(a) # {'key1': [1, 2, 3, 4], 'key2': {'nested': 42}, 'key3': '456'}
print(b) # {'key1': [1, 2, 3, 4], 'key2': {'nested': 42}, 'key3': '456'}
可以发现怎么更改a
,b
都随着改变
因为b=a
仅仅是建立了对象的引用,也就是a
、b
同时引用了字典对象而已
所以赋值不能算是拷贝❗❗❗
赋值(引用)不是拷贝,赋值(引用)不是拷贝,赋值(引用)不是拷贝!
要记住这点,这是引用,不是拷贝❗❗❗
这仅仅是引用,不算拷贝
copy
字典有个copy
方法,该方法创建并返回字典的浅拷贝。
示例
a = {"key1": [1, 2, 3], "key2": {"nested": 42}, "key3": "123"}
# 使用 copy 方法创建一个浅拷贝
b = a.copy()
# 修改key3的值
a["key3"] = "456"
print(a) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '456'}
print(b) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '123'}
# 修改key1的值
a["key1"].append(4)
print(a) # {'key1': [1, 2, 3, 4], 'key2': {'nested': 42}, 'key3': '456'}
print(b) # {'key1': [1, 2, 3, 4], 'key2': {'nested': 42}, 'key3': '123'}
可以发现,我们尝试修改了a
变量 key3
的值(不可变数据类型),b
变量没有跟着改变
我们修改a
变量 key1
的值(可变数据类型),b
变量跟着改变了
这就是上面说过的,要看数据类型是否可变才知道是采用引用还是新建立对象
由于key3
的值原先是不可变数据类型,所以只能新建立对象
而由于key1
的值是可变数据类型,所以是对[1, 2, 3]
对象的引用,而非建立新对象
解包
Python 3.5开始,可以使用双星号 **
来解包字典,从而创建一个新的字典(浅拷贝)。
相比较copy
个人感觉这个更有范🙃,作用与copy
相同,只是写法不同
a = {"key1": [1, 2, 3], "key2": {"nested": 42}, "key3": "123"}
# 使用 copy 方法创建一个浅拷贝
b = {**a}
# 修改key3的值
a["key3"] = "456"
print(a) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '456'}
print(b) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '123'}
# 修改key1的值
a["key1"].append(4)
print(a) # {'key1': [1, 2, 3, 4], 'key2': {'nested': 42}, 'key3': '456'}
print(b) # {'key1': [1, 2, 3, 4], 'key2': {'nested': 42}, 'key3': '123'}
deepcopy
上面提到的都是浅拷贝,那如果想要建立一个全新的字典副本,该怎么做?
这时候就得使用深拷贝了
使用内置模块 copy
的 deepcopy
方法
import copy
a = {"key1": [1, 2, 3], "key2": {"nested": 42}, "key3": "123"}
# 使用 deepcopy 方法创建一个深拷贝
b = copy.deepcopy(a)
# 修改key3的值
a["key3"] = "456"
print(a) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '456'}
print(b) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '123'}
# 修改key1的值
a["key1"].append(4)
print(a) # {'key1': [1, 2, 3, 4], 'key2': {'nested': 42}, 'key3': '456'}
print(b) # {'key1': [1, 2, 3], 'key2': {'nested': 42}, 'key3': '123'}
可以发现a
与b
是2个互不影响的字典,a
做出改变,b
不会做出改变
总结
- 概念
- 引用:可变数据、不可变数据对象均引用
- 深拷贝:可变数据、不可变数据对象均建立新副本
- 浅拷贝:可变数据使用对象的引用(如列表、字典等),不可变数据建立新副本
- 引用
- 赋值
- 深拷贝:
deepcopy()
- 浅拷贝
copy()
- 解包