浅拷贝 赋值 和 copy.copy()
Python中的浅拷贝分为直接赋值和使用copy
模块的copy
方法来进行浅拷贝。
赋值
先来看直接赋值的例子:
a = [1,2,3]
b = a
print( b is a) # True
很简单,就是两个变量指向同一个内存地址。
copy.copy()
- 对于不可变类型来说
对于不可变类型,copy.copy()
的表现形式和直接赋值是一样的,并不会重新创建一个新的对象,而是仅仅把新的变量指向原先的同一个地址上:
import copy
a = [1,2,3]
b= [4,5,6]
c = (a,b) # c为不可变类型
print( id(c) ) # 140065869930632
d = copy.copy(c)
print( id(d) ) # 140065869930632
print(d is c) # True
可以看到,对于不可变类型,使用d = copy.copy(c)
就相当于直接赋值d = c
- 对于可变类型来说
对于可变类型,copy.copy()
会创建于一块新的内存地址,然后仅仅拷贝目标对象的第一层,来看例子:
import copy
a = [1,2,3]
b= [4,5,6]
c = [a,b] # c为可变类型
d = copy.copy(c)
print( id(c) ) # 140393314515528
print( id(d) ) # 140393343993800
print(d is c) # False
# 说明创建了一块新的内存地址
a.append(4)
print(c) # [[1, 2, 3, 4], [4, 5, 6]]
print(d) # [[1, 2, 3, 4], [4, 5, 6]]
上述例子中,可以看到copy()
是创建了一个新的内存地址的,但是并没有将内部的a和b的两个引用也一起拷贝,而是仅仅拷贝了第一层,所以改变了a指向的对象之后,浅拷贝出来的d也会相应的改变。
深拷贝 copy.deepcopy()
针对上面对于可变类型,copy.copy()
仅仅会拷贝第一层的问题,我们可以使用copy.deepcopy()
来进行深度拷贝,进行deepcopy()
时,对象内部的引用指向的内存地址也会被拷贝,即会重新创建一份目标对象中的引用指向的内存地址。 来看下面例子:
import copy
a = [1,2,3]
b = [4,5,6]
c = [a,b]
d = c
e = copy.deepcopy(c)
a.append(4)
print(c) # [[1, 2, 3, 4], [4, 5, 6]]
print(e) # [[1, 2, 3], [4, 5, 6]]
# 说明深拷贝deepcopy的时候,如果拷贝的对象内部还接着有引用,那么依次进行内部的拷贝
如果上面例子不够直观,那么可以这么来理解:
import copy
a = [1,2,3]
b = [4,5,6]
c = [a,b]
d = c
e = copy.deepcopy(c)
print( id(c[0]) ) # 140623323590920
print( id(e[0]) ) # 140623323492232
# e的第一个元素的地址,和c第一个元素的地址是不一样的
print( c[0] is a ) # True
print( e[0] is a ) # False
# 意味着e内部将a和b两个变量指向的对象也进行了一份拷贝,而不是跟copy.copy()一样沿用
# c内部的a和b的地址(即只拷贝第一层)