引用
当对象是不可变类型的时候,int、float、double、string、tuple(纯tuple),遇到“引用”问题时,虽然起初两个变量指向同一个内存地址,但是改变了其中一个值,并不会影响另外一个(会重新开辟内存地址)。
当对象是可变类型的时候,list、dic,遇到“引用”问题,会一直共享一块内存地址,改变了其中一个,另外一个也就改变了。
#1 不可变量,更改后内存地址发生改变
a = 1
b = a
a = a+1
print('values {} id {}'.format(a,id(a)))
print('values {} id {}'.format(b,id(b)))
output:
values 2 id 1545235968
values 1 id 1545235936
# 2 可变类型,更改后内存地址不变
l1 = [1,2,[3,4],5]
l2 = l1
print(id(l1))
print(id(l2))
l1.append(6)
print(l2)
#output:
911276241736
911276241736
[1, 2, [3, 4], 5, 6]
浅拷贝(shallow copy):指重新分配一块内存,创建一个新的对象,里面的元素是原对象中子对象的引用。
三种浅拷贝的方法:
import copy
l1 = [1,2,[3,4],5]
#1 利用[:]
l2 = l1[:]
print('1: {} \t {}'.format(id(l1),id(l2)))
#2 利用copy.copy()
l2 = copy.copy(l1)
print('2: {} \t {}'.format(id(l1),id(l2)))
#3 利用list.copy()
l2 = l1.copy()
print('3: {} \t {}'.format(id(l1),id(l2)))
output:
1: 911276084616 911247796040
2: 911276084616 911276277704
3: 911276084616 911247796040
它会有一个问题,就是更改list中的list结构,会使整体改变。
l1 = [1,2,[3,4],5]
l2 = l1[:]
#1 浅层更改
l1.append(6)
print('1: {} \t {}'.format(l1,l2))
output:
1: [1, 2, [3, 4], 5, 6] [1, 2, [3, 4], 5]
#2 深层更改
l1[2].append(6)
print('2: {} \t {}'.format(l1,l2))
output:
2: [1, 2, [3, 4, 6], 5] [1, 2, [3, 4, 6], 5]
我的理解就是:
不可变的就是不可变,可变的里面如果是可变的那就是可变,可变的里面不可变那就是不可变。
在#1中,l1.append(6) 不会改变,因为6是和1,2,5同等级的,int型不可变。
但是在#2中,l1[2].append(6),浅拷贝会变,因为它的等级不是int而是list,list可变。
深拷贝:是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联。
import copy
l1 = ['a',['b','c'],'d']
l2 = copy.deepcopy(l)
l1[1].append('m')
print(l1)
print(l2)
output:
['a', ['b', 'c'], 'd']
['a', ['b', 'c', 'm'], 'd']
所以涉及到列表的嵌套结构的时候,还是用deepcopy()比较好,以防万一。
参考: