python 引用、copy 与deepcopy
一、引用
a=[1,2,3]
b=a
此为列表引用,a和b的内存地址是一样的,都是指向列表[1,2,3]。其实是一个列表,两个名字。操作其中一个变量改变列表,另外一个变量显示的列表也同时改变。
a=[1,2,3] b=a print(id(a)) print(id(b))
输出:
2132799892168
2132799892168
a.append(4) print(b) 输出:
[1, 2, 3, 4]
def lis(li): li.append(4) a=[1,2,3] lis(a) print('a=',a) 输出: a= [1, 2, 3, 4]
可以看到,即使函数没有返回值,列表a的内容也是被改变了。
这是因为不管变量名有多少个,列表其实只有一个。通过任意一个变量名对列表进行操作,列表改变,不管通过哪一个变量名引用列表的内容自然也发生改变。
引用与C语言的指针非常相像。
举个例子:一个人有两个名字张三、李四。如果张三中了500万,那么李四肯定中了500万。李四有1000万财产,张三肯定也有1000万财产。
此处,这个人就相当于列表。张三、李四这两个名字相当于变量名,指向这个人。这个人还可以叫王五、赵六。只要一个名字对应的这个人发生了改变,引用其余的名字时,这个人必然发生了同样的改变。
由于引用是对一个列表进行操作,列表会随着操作进行改变,无法保存原列表。
二、deepcopy
import copy
a=[1,2,[1,3]] b=copy.deepcopy(a) print(id(a)) print(id(b))
print(id(a[2]))
print(id(b[2]))
输出:
2599508758664
2599508759880
2239363432264
2239363470600
a、b的内存地址已经完全不一样,a、b指向的列表完全相互独立,是两个完全不同的列表,相互之间不再存在影响。
三、copy
copy是介于引用和deepcopy之间的一种模式。
对于最外层的列表,相当于deepcopy,相互独立。
但是对于嵌套的列表,他相当于引用
a=[1,2,[1,3]] b=a.copy() print(id(a)) print(id(b)) print(id(a[2])) print(id(b[2])) 输出结果: 3166059548808 3166059550024 3166059511624 3166059511624
可以看到,对于a、b这两个变量,他们的内存地址是不一样的,相互独立
但是对于嵌套列表a[2]、b[2]来说,内存地址是一样的,是对同一个列表的引用。
同样,对于一个列表a添加一个列表b作为元素,则该元素也会随着列表b的变化而变化
a=[1,2,3] b=[4,5,6] a.append(b) b[0]=0 print(a) 输出: [1, 2, 3, [0, 5, 6]] #可以看到,当b改变后,a[3]也随之改变 若想相互独立,由于b中元素不含有列表,此处可以用copy: a=[1,2,3] b=[4,5,6] a.append(b.copy()) b[0]=0 print(a) 输出: [1, 2, 3, [4, 5, 6]] 如果b中同样嵌套列表,则需要用deepcopy