Python深浅拷贝&引用详解
一、定义
浅拷贝:只复制最外层的结构,除最外层其余的直接将其地址引用过来。
深拷贝:全部数据/结构都进行复制,(除不可变类型)增大数据独立性,如果深拷贝中,只要发现复制数据中有一个不是不可变类型就重新创建。
python的数据分为可变类型和不可变类型,可变类型有:list,dict,set。不可变类型:number,string,tuple。所以我们分为不可变类型和可变类型两方面来理解深拷贝和浅拷贝。
二、不可变类型拷贝
1.不可变类型
#不可变类型
a = 'abc'
b = 'abc'
print("c的地址:{}".format(id(c)))
print("d的地址:{}".format(id(d)))
#结果
a的地址:57188256
b的地址:57188256
结论:对于不可变类型,a和b指向同一个地址,说明a和b是同一个对象。
2.浅拷贝(可变类型)
a = [1,2,3,4,['a','b']]
b = copy.copy(a)
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:[1, 2, 3, 4, ['a', 'b']],a的地址:50240408
b:[1, 2, 3, 4, ['a', 'b']],b的地址:50352856
# 对其中不可变元素进行修改
a.append(5)
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:[1, 2, 3, 4, ['a', 'b'], 5],a的地址:50240408
b:[1, 2, 3, 4, ['a', 'b']],b的地址:50352856
#对其中可变元素进行修改
a[4].append('c')
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:[1, 2, 3, 4, ['a', 'b', 'c'], 5],a的地址:50240408
b:[1, 2, 3, 4, ['a', 'b', 'c']],b的地址:50352856
结论:对于内层的可变类型数据元素,拷贝的是其地址。当修改其中的不可变类型数据,拷贝后的对象不会跟着改变,如果修改其中的可变类型对象,拷贝后的对象会跟着一起改变。
3.浅拷贝(不可变类型)
a = 'abcdef'
b = copy.copy(a)
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:abcdef,a的地址:20235456
b:abcdef,b的地址:20235456
#修改
a = 'abc'
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:abc,a的地址:20160416
b:abcdef,b的地址:20235456
结论:浅拷贝对于不可变类型,类似于直接赋值。
三、可变类型拷贝
1.可变类型
#可变类型
c = [1,2,3]
d = [1,2,3]
print("a的地址:{}".format(id(a)))
print("b的地址:{}".format(id(b)))
#结果
c的地址:59068744
d的地址:58956776
结论:对于可变类型,c和d是两个不同的对象。
2.深拷贝(可变类型)
a = [1,2,3,4,['a','b']]
b = copy.deepcopy(a)
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:[1, 2, 3, 4, ['a', 'b']],a的地址:58497944
b:[1, 2, 3, 4, ['a', 'b']],b的地址:58610392
# 对其中不可变元素进行修改
a.append(5)
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:[1, 2, 3, 4, ['a', 'b'], 5],a的地址:58497944
b:[1, 2, 3, 4, ['a', 'b']],b的地址:58610392
#对其中可变元素进行修改
a[4].append('c')
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:[1, 2, 3, 4, ['a', 'b', 'c'], 5],a的地址:58497944
b:[1, 2, 3, 4, ['a', 'b']],b的地址:58610392
结论: 深拷贝是将原对象里面的所有元素全部拿出来,然后重新用新的内存空间存储,原对象和拷贝后的对象就没有任何关系了,不管原对象如何改变,拷贝后的对象都不会变。
3.深拷贝(不可变类型)
a = 'abcdef'
b = copy.deepcopy(a)
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:abcdef,a的地址:48809152
b:abcdef,b的地址:48809152
#修改
a = 'abc'
print("a:{},a的地址:{}".format(a,id(a)))
print("b:{},b的地址:{}".format(b,id(b)))
#结果
a:abc,a的地址:48734112
b:abcdef,b的地址:48809152
结论 :对于不可变类型,不管深浅拷贝,拷贝的都是其引用,一旦原对象改变,就相当于是一个新的对象了,拷贝后的对象与原对象没有任何关系了。
四、扩展
引用与赋值:在python中的赋值,实际上都是引用,内在的含义就是用一个标签指向这个内存空间。
x = 10
结论:该语句在执行时,实际上是先在内存空间中创建一个10,然后将x标签指向这个内存空间,因此这才是完整的引用操作。python中所有的赋值操作都是引用,而不是复制这个内存空间创建一个新的空间来存放这个值。
五、引用
[1]https://blog.csdn.net/time_money/article/details/109604550
[2]https://blog.csdn.net/weixin_43959953/article/details/86249452