有一次面试的时候被问到了,记录一下。
python中对于对象的拷贝分为两种方式:深拷贝和浅拷贝。浅拷贝用‘=’实现,深拷贝则使用deepcopy()函数完成。浅拷贝和深拷贝的区别是:浅拷贝只是将原对象在内存中引用地址拷贝过来了,让新的对象指向这个地址,这样新对象与原对象指向的地址相同;而深拷贝是将这个对象的所有内容拷贝过来了,包括值与内存地址,所以如果你这时候修改原来对象的值跟新对象没关系了,不会随之更改。
举个栗子。
先看浅拷贝
# 1.使用=复制不可变对象的值。
a = 1
b = a
print("a is :{0},b is :{1}".format(a, b)) # a is :1,b is :1
print(id(a), id(b)) # 2012967568 2012967568 此时a,b指向相同内存地址
# 这时候修改a的值,因为a是不可变类型,修改其值,会重新给新值分配内存,然后指向他。
a += 1
print(a, id(a), b, id(b)) # 2 2012967600 1 2012967568 值不一样,内存地址也不一样了
# 1.使用=复制可变对象的值。
ls1 = [1, 2, 3, 4]
ls2 = ls1
print("ls1 is :{0},ls2 is :{1}".format(ls1, ls2)) # ls1 is :[1, 2, 3, 4],ls2 is :[1, 2, 3, 4]
print(id(ls1), id(ls2)) # 1815774582984 1815774582984 直接使用=复制变量,内存地址一样,值也一样。
# 这时候修改可变对象的值,因为其值可变,所以只需要在原内存地址上修改即可。
ls1.append(5)
print(id(ls1), id(ls2)) # 1815774582984 1815774582984 可变对象修改其值,内存引用不变
print(ls1, ls2) # [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] 因为两个变量的内存指向一样,所以值也一样。
再看深拷贝
# 1.使用copy.deepcopy()拷贝不可变对象的值。
a = 1
b = copy.deepcopy(a)
print("a is :{0},b is :{1}".format(a, b)) # a is :1,b is :1
print(id(a), id(b)) # 2012967568 2012967568 对于不可变对象,深度拷贝内存地址没有修改。
a += 1
print(a, id(a), b, id(b)) # 2 2012967600 1 2012967568 值不一样,内存地址也不一样了
# 1.使用copy.deepcopy()复制可变对象的值。
ls1 = [1, 2, 3, 4]
ls2 = copy.deepcopy(ls1)
print("ls1 is :{0},ls2 is :{1}".format(ls1, ls2)) # ls1 is :[1, 2, 3, 4],ls2 is :[1, 2, 3, 4]
print(id(ls1), id(ls2)) # 2585490905224 2585490905032 注意对于可变对象深度拷贝后内存地址不一样了。
ls1.append(5)
print(id(ls1), id(ls2)) # 2585490905224 2585490905032
print(ls1, ls2) # [1, 2, 3, 4, 5] [1, 2, 3, 4] 注意这个时候ls2的值没有随着ls1修改。
总结:其实对于浅拷贝和深拷贝来说,如果拷贝对象都是不可变对象的话,那么两者效果是一样的。如果是可变对象的话,“=”拷贝的方式,只是拷贝了内存中的地址引用,两个对象的地址引用一样,所以两个对象的值会随着一方的修改而修改。而对于deepcopy()来说,如果是可变对象的话,那么拷贝内容后新对象的内存地址也会重新分配,跟原来的内存地址不一样了,所以两者任意修改变量的内容不会对另一方造成影响。
参考: