在python中,对象的赋值往往是通过“=”进行的。但是由于“=”右边的类型方式不一样,所以产生变量虽然值相同,但是在内存中的地址值不同,可能会造成内存空间的浪费。如题所示,对象赋值中存在三种类型情况的赋值
引用赋值
引用赋值l2=l1 ,首先创建个变量l2,然后在创建一条引用,把这条引用指向l1的地址值。然后l1和l2共同使用这一块地址值。
当l1进行变化后,l2也跟着变化
l1= ['hello']
l2= l1
print(id(l1),id(l2) ) #1580262888480 1580262888480
print(l1,l2) # ['hello'] , ['hello']
print(l1 is l2) # true
l1.append("word")
print(l1,l2) ['hello', 'word'] ['hello', 'word']
print(id(l1),id(l2) )
print(l1 is l2) #true
浅拷贝
浅copy后,对象的内存地址,指的不是同一个内存地址。浅copy可以通过 对象.copy() 或者 对象切片截取对象[:] 浅拷贝,对于内部的不可变对象,拷贝后,原对象修改后,拷贝对象不修改。 浅拷贝,对于内部的可变对象,拷贝后,原对象修改,拷贝对象也修改。 浅拷贝创建了新的对象,但是只拷贝了序列的元素,对于元素也是一个序列的情况(即子对象),只复制了对这个序列的引用!
list0=[9,2,3,'4',[4.5,[4.55],4.6]]
list1=list0.copy() #浅copy,地址值变了
print(id(list0),id(list1)) # 1199787477320 1199787477256
print(list0,list1) #[9, 2, 3, '4', [4.5, [4.55], 4.6]] [9, 2, 3, '4', [4.5, [4.55], 4.6]]
list0[0]=0
list0[4][0]=38
list0[4][1].append(4.66)
print(list0,list1) $ [0, 2, 3, '4', [38, [4.55, 4.66], 4.6]] [9, 2, 3, '4', [38, [4.55, 4.66], 4.6]]
深拷贝
深拷贝 deepcopy()是在另一块地址中创建一个新的变量或容器,
同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本,已经切断他们之间所有的联系。
深拷贝 拷贝对象及其子对象,拷贝后原对象做任何变化,copy的对象都不会做变化。
深拷贝是完完全全的拷贝,把原对象完整地拷贝到了新对象中。
list9=[1,2,'3',[4,[4.5],5],6,7]
list8=copy.deepcopy(list9)
print(id(list8) ,id(list9))
print(list8,list9)
list9[2]=0
list9[3][0]=3.99
list9.append(8)
print(list8,list9)
print(id(list8),id(list9))
# 深copy后的对象 #原对象
2339307915016 2339307915080
[1, 2, '3', [4, [4.5], 5], 6, 7] [1, 2, '3', [4, [4.5], 5], 6, 7]
[1, 2, '3', [4, [4.5], 5], 6, 7] [1, 2, 0, [3.99, [4.5], 5], 6, 7, 8]
2339307915016 2339307915080
关于赋值拷贝,浅拷贝,深拷贝的具体适用场景:
当我们仅仅想适用某个对象的值的时候,我们就应该适用深拷贝,来切断他与原拷贝对象的关系,以免随着拷贝对象的变化而变化,但是从内存方面,又多占用内存空间;
当我们想加深连个对象之间的联系,就应使用“引用”
对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有被拷贝一说,因为他们每次创建都是同一个地址值。
如果元祖变量只包含原子类型对象,则不能深拷贝。
ll=[0,1,2,3,4,5,6,7,8,9] #为这个列表增加一组可变的子元素 ll.append([888888,99999]) import copy from copy import deepcopy ''' 引用赋值,浅copy, 深copy ''' #分别产生对象的数据 l3=ll #赋值 l2=ll.copy() #浅拷贝 l4=deepcopy(ll) #深copy #操作:对于不可变的子元素操作 ll.append('10') l2.append('12') l3.append('13') #由于引用赋值时,它还是在原对象上面修改的。所以会追加2次操作 l4.append('14') print(ll,l2,l3) print("浅copy的对象是个列表,对于不可变的对象,修改原不可变对象是不受影响的") #操作:对于可变的子元素操作 ll[-3][0]=0 print(ll,l2,l4) #浅copy和赋值都会改变,深copy不会改变。 print("浅copy的对象是个列表,对于其内部的可变对象,如当前元素是列表下的一个子列表," " 修改它时会随着被copy对象的变化而变化") ''' 所以综上所述:当改变原对象后,想不影响copy后的元素使用, 第一种方式:使用浅copy时,并且确保里面的元素全部为不可变对象。 第二种方式:使用deepcopy,但是增加了内存开销。 '''