1. 铺垫知识:
Python3中,有6个标准的数据类型,他们又分为可变和不可变。
1.1 不可变数据(3个):
- Number(数字)
- String(字符串)
- Tuple(元组)
1.2可变数据(3个):
- List(列表)
- Dictionary(字典)
- Set(集合)
2. 浅拷贝和深度拷贝
2.1浅拷贝
2.1.1 copy模块里面的copy方法实现
- 对于不可变类型 Number、String、Tuple,浅复制仅仅是地址指向,不会开辟新空间。
- 列表项对于可变类型List、Dictionary、Set,浅复制会开辟新的空间地址(仅仅是最顶层开辟了新的空间,里层的元素地址还是一样的),进行浅拷贝
- 浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象的;改变原始对象中为不可变类型的元素的值,只有原始类型受影响。(操作拷贝对象对原始对象的也是同理)
2.2 深拷贝
2.2.1 copy模块里面的deepcopy方法实现
- 深拷贝,除了顶层拷贝,还对子元素也进行了拷贝(本质上递归浅拷贝)
- 经过深拷贝后,原始对象和拷贝对象所有的元素地址都没有相同的了
- 可以用切片表达式进行浅拷贝
- 字典的copy方法可以拷贝一个字典
- 深拷贝内部子元素如果是不可变类型,但内部子元素的子元素存在可变类型,则按照可变类型的递归浅拷贝对子元素进行拷贝
3. 可变类型和不可变类型在浅拷贝中的区别
3.1 不可变类型 Number String Tuple
对于不可 变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间拷贝值
import copy
num1 = 17
num2 = copy.copy(num1)
print("num1:" + str(id(num1)))
print("num2:" + str(id(num1)))
# num1和num2的地址都相同
str1 = "hello"
str2 = copy.copy(str1)
print("str1:" + str(id(str1)))
print("str2:" + str(id(str2)))
# str1和str2的地址都相同
tup1 = (18, "tom")
tup2 = copy.copy(tup1)
print("tup1:" + str(id(tup1)))
print("tup2:" + str(id(tup2)))
# tup1和tup2的地址都相同
print("="*20)
3.2 可变类型 List、Dictionary、Set
对于可变类型 List、Dictionary、Set,浅复制会开辟新的空间地址(仅仅是最顶层开辟了新的空间),进行浅拷贝
list1 = [11,12]
list2 = copy.copy(list1)
print("list1:" + str(id(list1)))
print("list2:" + str(id(list2)))
# list1和list2的地址不相同
dic1 = [11,12,"hi"]
dic2 = copy.copy(dic1)
print("dic1:" + str(id(dic1)))
print("dic2:" + str(id(dic2)))
# dic1和dic2的地址不相同
set1 = {"AA","BB"}
set2 = copy.copy(set1)
print("set1:" + str(id(set1)))
print("set2:" + str(id(set2)))
# set1和set2的地址不相同
3.3 对于不可变类型被修改后造成的影响,我们用一个更加简单的例子便可更好理解:
num = 123
print(str(id(num)))
num = 666
print(str(id(num)))
console:
4348603632
4350009296
4. 深拷贝对6种基本类型的影响
我们对3种可变类型3种不可变类型进行深拷贝。
结果发现,和浅拷贝几乎一致。
其实这也好理解,因为深拷贝对比浅拷贝,强调的是递归,强调的是子元素。
对顶层的操作,深浅拷贝无异。
4.1 不可变类型 Number String Tuple
对于不可 变类型 Number String Tuple,深复制依然是地址指向,不会开辟新空间拷贝值
import copy
num1 = 17
num2 = copy.deepcopy(num1) # 深拷贝
print("num1:" + str(id(num1)))
print("num2:" + str(id(num1)))
# num1和num2的地址都相同
str1 = "hello"
str2 = copy.deepcopy(str1) # 深拷贝
print("str1:" + str(id(str1)))
print("str2:" + str(id(str2)))
# str1和str2的地址都相同
tup1 = (18, "tom")
tup2 = copy.deepcopy(tup1) # 深拷贝
print("tup1:" + str(id(tup1)))
print("tup2:" + str(id(tup2)))
# tup1和tup2的地址都相同
print("="*20)
4.2可变类型 List、Dictionary、Set
对于可变类型 List、Dictionary、Set,深拷贝会开辟新的空间地址,进行拷贝
list1 = [11,12]
list2 = copy.deepcopy(list1) # 深拷贝
print("list1:" + str(id(list1)))
print("list2:" + str(id(list2)))
# list1和list2的地址不相同
dic1 = [11,12,"hi"]
dic2 = copy.deepcopy(dic1) # 深拷贝
print("dic1:" + str(id(dic1)))
print("dic2:" + str(id(dic2)))
# dic1和dic2的地址不相同
set1 = {"AA","BB"}
set2 = copy.deepcopy(set1) # 深拷贝
print("set1:" + str(id(set1)))
print("set2:" + str(id(set2)))
# set1和set2的地址不相同
4.3浅拷贝的会对子元素也进行拷贝
import copy
l1 = [11, 12]
l2 = [21, 22]
num = 555
allOne = [l1, l2,num]
# 深拷贝,除了顶层拷贝,还对子元素也进行了拷贝(本质上递归浅拷贝)
# 经过深拷贝后,原始对象和拷贝对象所有的元素地址都没有相同的了
allOne2 = copy.deepcopy(allOne) # copy.deepcopy 深拷贝
allOne[1] = [113,114]
allOne2[2] = [227,228]
print(allOne)
print(allOne2)
print("id allOne:"+str(id(allOne)))
print("id allOne[0]:"+str(id(allOne[0])))
print("id allOne[1]:"+str(id(allOne[1])))
print("id allOne[2]:"+str(id(allOne[2])))
print("===")
print("id allOne2:"+str(id(allOne2)))
print("id allOne2[0]:"+str(id(allOne2[0])))
print("id allOne2[1]:"+str(id(allOne2[1])))
print("id allOne2[2]:"+str(id(allOne2[2])))
console
[[11, 12], [113, 114], 555]
[[11, 12], [21, 22], [227, 228]]
id allOne:4549589640
id allOne[0]:4554067720
id allOne[1]:4554067848
id allOne[2]:4548329424
===
id allOne2:4554067912
id allOne2[0]:4554067784
id allOne2[1]:4554067592
id allOne2[2]:4554100808
本例是跟浅拷贝做对比的。
在之前的浅拷贝中,子元素是不会开辟新空间做拷贝的。
而在深拷贝中,子元素也进行了拷贝。
5. 其他拷贝方式
除了copy模块的中的copy和deepcopy,还有其他自带的方式可实现拷贝。
- 分片表达式进行浅拷贝
- 字典的copy方法可以拷贝一个字典
5.1 分片表达式拷贝
l1 = [11, 12]
l2 = [21, 22]
num = 555
orgi = [l1, l2, num]
nList = orgi[:]
print("orgi:"+str(id(orgi)))
print("orgi[0]:"+str(id(orgi[0])))
print("orgi[1]:"+str(id(orgi[1])))
print("orgi[2]:"+str(id(orgi[2])))
print("*"*30)
print("nList:"+str(id(nList)))
print("nList[0]:"+str(id(nList[0])))
print("nList[1]:"+str(id(nList[1])))
print("nList[2]:"+str(id(nList[2])))
用分片表达式进行的拷贝,是浅拷贝。
5.2 字典自带的copy方法可实现深拷贝
dic = {"key": "hello", "num": 18}
dic2 = dic.copy()
dic["key"] = "one"
dic2["key"] = "two"
print(dic)
print("dic:" + str(id(dic)))
print(dic2)
print("dic2:" + str(id(dic2)))
console:
{'key': 'one', 'num': 18}
dic:4382946792
{'key': 'two', 'num': 18}
dic2:4382946864