前言
由于python关于传参的方面和C语言有些出入,对于先学C在学Python的可能需要做些笔记,比如Python中def传参是直接传址,而不是传值创建局部变量等等...而到了copy函数感觉又是个新概念...
1. copy介绍
1.1 copy() 浅拷贝
Python 的 copy()
函数是 copy
模块提供的一个用于创建对象浅拷贝的工具。浅拷贝意味着新创建的对象与原始对象在内存中是两个独立的实体,但是它们包含的数据如果是可变的(比如列表、字典等),那么这些可变数据内部的元素仍然是指向原始对象的引用。
1.2 deepcopy()深拷贝
Python 的 deepcopy()
函数是 copy
模块提供的另一个工具,用于创建对象的深拷贝。与浅拷贝不同,深拷贝会递归地复制对象及其所有子对象,直到所有的元素都是新的副本,新对象和原始对象不再共享任何数据。
2.代码实现
2.1 浅拷贝
首先创建一个list类型a里面要存放[10,20]并另外一个list对象[5,6],进行浅拷贝到b
import copy
# 浅拷贝
print("浅拷贝:")
a = [10,20,[5,6]]
b = copy.copy(a)
print("a = ",a)
print("b = ",b)
# 由于浅拷贝,只是会拷贝表象,所以把a的对象是直接引用,不会拷贝的,
#在b中修改对象之后就会直接修改掉a引用的对象
b.append(30)
b[2].append(7)
print("Aftercopy_a = ",a)
print("Aftercopy_b = ",b)
在对list b最后添加一个30,和在[5,6]中添加一个7,发现输出:
浅拷贝:
a = [10, 20, [5, 6]]
b = [10, 20, [5, 6]]
Aftercopy_a = [10, 20, [5, 6, 7]]
Aftercopy_b = [10, 20, [5, 6, 7], 30]
拷贝之后不正常的地方在于,a中的[5,6]对象也被修改了,这是因为浅拷贝时 b会直接引用源对象的引用而不会拷贝一份,所以改变b的引用也会改变a的引用。
当创建变量a时,会在堆中创建对象(从左往右),栈中创建变量,指向堆中的对象,而对象开始会开辟三块空间,前两块存放10,20,第三块存放的地方指向另外一个对象,就是[5,6]
当浅拷贝后b就不一样了,b会拷贝表象(就是只开辟第一层的对象),但是第二层的对象([5,6])则会直接进行引用,所以当b.append(30)之后,b会在自己开辟的对象进行添加,而执行b[2].append(7),因为b[2]指向的就是a的[5,6],所以,a也会一起被添加7,而没有添加30。
2.2 深拷贝
理解完浅拷贝深拷贝就很好理解了,就是一模一样全部对象拷贝过来,互不影响
# 深拷贝
print("深拷贝:")
c = [10,20,[5,6]]
d = copy.deepcopy(c)
print("c = ",c)
print("d = ",d)
# 深拷贝就会把拷贝源头实现再复现一遍,在拷贝过后怎么修改都不会影响拷贝源
d.append(30)
d[2].append(7)
print("Aftercopy_c = ",c)
print("Aftercopy_d = ",d)
深拷贝:
c = [10, 20, [5, 6]]
d = [10, 20, [5, 6]]
Aftercopy_c = [10, 20, [5, 6]]
Aftercopy_d = [10, 20, [5, 6, 7], 30]
a,b指向的对象相互独立,所以只会添加在b中
3. 区别总结
-
拷贝深度:
copy()
创建的是浅拷贝(Shallow Copy)。这意味着新对象只会复制原始对象中的引用,而不是引用所指向的对象本身。因此,如果原始对象包含任何可变对象,如列表或字典,修改这些可变对象会影响到原始对象和拷贝对象。deepcopy()
创建的是深拷贝(Deep Copy)。新对象会递归地复制原始对象以及所有被引用的对象。这意味着新对象和原始对象完全独立,修改新对象不会影响原始对象。
-
性能:
- 由于
copy()
只是复制引用,它通常比deepcopy()
快,并且使用的内存较少。 deepcopy()
需要递归地复制所有对象,这可能会消耗更多的时间和内存,特别是当对象包含大量数据或复杂嵌套结构时。
- 由于
-
用途:
- 当你只需要复制对象的顶层结构,并且不需要关心对象内部的可变子对象时,使用
copy()
。 - 当你需要完全独立的副本,包括对象内部的所有嵌套对象时,使用
deepcopy()
。
- 当你只需要复制对象的顶层结构,并且不需要关心对象内部的可变子对象时,使用
-
自定义行为:
- 如果对象是自定义类实例,
copy()
可以通过定义对象的__copy__()
方法来自定义其行为。 - 对于
deepcopy()
,则可以通过定义__deepcopy__()
方法来自定义深拷贝的行为。
- 如果对象是自定义类实例,
-
对不可变数据的影响:
- 对于不可变数据类型(如整数、字符串、元组等),
copy()
和deepcopy()
之间没有区别,因为这些类型的数据不可更改,复制只是创建了数据的引用。
- 对于不可变数据类型(如整数、字符串、元组等),
-
对内部结构的影响:
- 使用
copy()
时,原始对象和拷贝对象共享内部的可变子对象。 - 使用
deepcopy()
时,原始对象和拷贝对象的内部结构是完全独立的。
- 使用