前言
在Python中,Python对象的赋值,深浅拷贝之间是有差异的,今天就来总结一下三者之间的区别.
对象赋值
直接看一下代码(Python3):
list1 = ["test", 28, ['a', 'b', 'c']]
list2 = list1
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
list2 is list1
list2[2] is list1[2]
list1[0]="test2"
list1[2].append('d')
print(list1)
print(list2)
print([id(element) for element in list1])
print([id(element) for element in list2])
现在简单分析一下上面的代码:
- 创建list对象赋值给为list1变量
- 然后把list1赋值给变量list2,实际上list2变量将指向list1变量对应的对象(内存地址),也就是说"list2 is list1","list2[i] is list1[i]",Python中,对象的赋值都是进行对象引用(内存地址)传递
3.修改list[0]和list[2]的子list值,由于str是不可变类型,所以修改list[0]时会更换新旧对象,产生一个新的地址。如下图:
浅拷贝
下面看一下浅拷贝的代码:
import copy
list1 = ["test", 28, ['a', 'b', 'c']]
list2 = copy.copy(list1)
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
list2 is list1
list1[2] is list1[2]
list1[0]="test2"
list1[2].append('d')
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
继续分析上面的的代码:
1.当变量list1浅拷贝给变量list2的时候,就相当于创建一个新对象,两者的id不同,因此list1 is not list2
2.然而,list2中的元素id是一样的。因此说明,浅拷贝中的对象的元素是之前的原始元素的引用,所以list1[i] is list2
3.当对list1进行修改时,因为list1的第一个元素是不可变对象,所以会使用一个新的对象
4330292760
,而list2还是指向原始元素的引用4330291808
;当修改第三个元素时,由于是可变对象,所以不会产生一个新的对象,只修改里面的元素,所以还是4331291992
,如图
深拷贝
下面看一下深拷贝:
import copy
list1 = ["test", 28, ['a', 'b', 'c']]
list2 = copy.deepcopy(list1)
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
list2 is list1
list1[2] is list1[2]
list1[0]="test2"
list1[2].append('d')
print(list1)
print(list2)
print(id(list1))
print(id(list2))
print([id(element) for element in list1])
print([id(element) for element in list2])
分析一下代码:
1.深拷贝,不仅创建一个新的对象list1,list1 is not list2
2.还会对对象中的可变元素创建新的对象,所以list1[2] is not list2[2]
3.list1[0]修改元素,会创建一个新的对象
4329244408
,list2[0]没有改变,还是4329243232
,所以list1修改不会影响list2
注意:
1.对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有拷贝这一说
也就是说,对于这些类型,"obj is copy.copy(obj)" 、"obj is copy.deepcopy(obj)"
- 如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子:
import copy
list1 = ('a', 'b', 'c')
list2 = copy.deepcopy(list1)
print(list1 is list2) #True
总结
本文介绍了对象的赋值和拷贝,以及它们之间的差异:
1.Python中对象的赋值都是进行对象引用(内存地址)传递
2.使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.
3.如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝
4.对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有被拷贝一说
5.如果元祖变量只包含原子类型对象,则不能深拷贝