1、赋值
对象之间赋值本质上是对象之间的引用传递,也就是多个对象指向同一个数据空间。当创建一个对象,把它赋值给另一个变量的时候,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已。原始数据改变,被赋值的对象数据也会做相同的改变。
(1)列表之间的赋值
a = [11,22]
b = a
print(id(a)) # 用来显示 a 指向的数据的内存地址
print(id(b)) # 用来显示 b 指向的数据的内存地址
运行结果:
1610957499464
1610957499464
结论:
以上结果相同,说明了当给一个变量赋值时,其实就是将数据的引用复制了一份给了另外一个变量,这其实就是最简单的浅拷贝。
类似于 xx1 = xx2 这种类型的基本都是浅拷贝。
(2)字典之间的赋值
c = {"name":"teacher"}
d = c
print(id(c))
print(id(d))
c["age"] = 20
print(c)
print(d)
运行结果:
3127108004240
3127108004240
{'name': 'teacher', 'age': 20}
{'name': 'teacher', 'age': 20}
2、浅拷贝
浅拷贝是对于一个对象的顶层拷贝,也就是只能拷贝最外面的一层。对于只有一层的数据可以完全拷贝;对于有多层数据的对象,只拷贝该对象的顶层,其余的只是把存放变量的地址值传给被赋值的对象,最后两个变量引用了同一份地址。通俗的理解是:拷贝了引用,并没有拷贝内容(指向了别人的内存地址,并没有建立一个新的内存地址)。
(1)对于只有一层数据的浅拷贝(完全拷贝,相当于深拷贝)
import copy
a = [1,2,3,4]
b = copy.copy(a)
print(a)
print(b)
print(id(a))
print(id(b))
a.append(9)
print(a)
print(b)
print(id(a))
print(id(b))
运行结果:
[1, 2, 3, 4]
[1, 2, 3, 4]
2076501879368
2076501879560
[1, 2, 3, 4, 9]
[1, 2, 3, 4]
2076501879368
2076501879560
(2)对于有两层数据的浅拷贝
1)查看id
a = [11, 22]
b = [33, 44]
c = [a, b]
print(id(a))
print(id(b))
print(id(c))
print(id(c[0]))
print(id(c[1]))
运行结果:
2163059240008
2163058363336
2163059239880
2163059240008
2163058363336
2)举例
import copy
a = [11, 22]
b = [33, 44]
c = [a, b]
d = copy.copy(c)
print(id(a))
print(id(b))
print(id(c))
print(id(d))
print(id(d[0]))
print(id(d[1]))
a.append(11)
print(c)
print(d)
运行结果:
2163059240008
2163058363336
2163059239880
2163060779784
2163059240008
2163058363336
[[11, 22, 11], [33, 44]]
[[11, 22, 11], [33, 44]]
结论:
C对象的顶层数据就是[a,b],所以通过浅拷贝给D对象时D对象中也是[a,b]。
浅拷贝,只会复制最顶层的那个列表。
3、深拷贝
深拷贝是对于一个对象所有层次的拷贝(递归)。深拷贝是在内存中建立了一个新的内存地址,并另建了相同的数据。
(1)深拷贝举例
import copy
a = [11, 22]
b = copy.deepcopy(a) # 对a指向的列表进行深拷贝
print(a)
print(b)
print(id(a))
print(id(b))
# 以上结果说明了通过deepcopy确实将a列表中所有的数据的引用拷贝了,而不是只拷贝了a指向的列表的引用
a.append(33)
print(a)
print(b)
运行结果:
[11, 22]
[11, 22]
2492948097608
2492948097800
[11, 22, 33]
[11, 22]
(2)进一步理解深拷贝
import copy
a = [11, 22]
b = [33, 44]
c = [a, b]
d = copy.deepcopy(c)
print(id(a))
print(id(b))
print(id(c))
print(id(c[0]))
print(id(c[1]))
print(id(d))
print(id(d[0]))
print(id(d[1]))
c[0].append(55)
print(c)
print(d)
运行结果:
1784636648008
1784636648200
1784635290184
1784636648008
1784636648200
1784635290312
1784635290376
1784636649224
[[11, 22, 55], [33, 44]]
[[11, 22], [33, 44]]
4、浅拷贝和深拷贝对不可变类型的拷贝
copy.copy对于可变类型,会进行浅拷贝。
copy.copy和copy.deepcopy对于不可变类型没有意义,全部等价于对象之间的赋值操作,即为引用的传递。
(1)浅拷贝对可变类型的copy
import copy
a = (11, 22, 33)
b = copy.copy(a)
print(id(a))
print(id(b))
运行结果:
2130815156424
2130815156424
(2)深拷贝对可变类型的copy
import copy
a = (11, 22, 33)
b = copy.deepcopy(a)
print(id(a))
print(id(b))
运行结果:
2341555192456
2341555192456
总结
(1)不可变对象类型,不管是深拷贝还是浅拷贝,地址值和拷贝后的值都是一样的。
(2)对于可变对象深浅拷贝:
- =(浅拷贝)浅拷贝:值相等,地址相等
- copy(浅拷贝):值相等,地址不相等
- deepcopy(深拷贝):值相等,地址不相等
(3)深浅拷贝的作用:
- 减少内存的使用。
- 以后在做数据的清洗、修改或者入库的时候,对原数据进行复制一- 份,以防数据修改之后,找不到原数据。