1. 变量与数据的地址概念
变量中存储的是数据的地址,以列表为例,列表是一个容器,当打印列表的时候实际上打印的是这个容器的地址,而非数据本身的地址,因此,列表的地址和列表内的数据的地址是不同的,两者之间没有什么联系。
# 列表(容器)和列表内数据的地址是不同的
numlist = ['abc', 10, True]
print(id(numlist)) #1620906551616
print(id(numlist[0]),id('abc')) #1620906432816
2. ==、is和is not
is/is not:判断两个变量的地址是否相同
==:判断两个变量的值是否相同
id(变量1) ==id(变量2):判断两个变量的地址是否相同,和is功能一样
对于不可变的数据类型【int/float/bool/str/tuple】:因为变量不可变,所以只有一个不变的地址,一份内存空间,值相同,地址也相同。
# 以数值型为例
n1 = 10
n2 = 20
print(n1 == n2) # False
print(n1 is n2) # False
print(id(n1) == id(n2)) # False
n3 = 10
print(n1 == n3) # True
print(n1 is n3) # True
print(id(n1) == id(n3)) # True
对于可变的数据类型【list/dict/set】:因为变量是可变的,相当于有两个容器去进行比较,只不过里面装的东西是一样的(打个比方,两个相同的水果篮,里面装着一模一样的水果),但实际这还是两个不同的容器,他们的值即使相同,地址也是不同的。
# 以列表为例
list1 = [10,20,30]
list2 = [10,20,30]
# 比较值
print(list1 == list2) # True
# 比较地址
print(list1 is list2) # False
print(id(list1) == id(list2)) # False
结论:
两个变量的地址相同,则这两个变量的值一定相同
两个变量的值相同,但这两个变量的地址不一定相同
3. 变量的拷贝
在什么时候需要对数据进行拷贝或备份呢?就是当数据的内容是可变的时候,因此,Python中可变数据的类型才有拷贝的功能。
拷贝分为浅拷贝和深拷贝:
浅拷贝:只会拷贝最外层
深拷贝:不管嵌套了多少层,都会拷贝
变量的拷贝主要有4种情况(以列表为例):
3. 1. = 引用赋值
以下图为例,使用引用赋值,相当于list1和list2相当于指向同一个内存空间,当对list1的某个元素进行修改时,list2的指针仍旧指向原来的地址空间,因此,使用=引用赋值无法起到拷贝的作用。
# 一维列表
list1 = [11,22,33]
list2 = list1
print(list2 is list1) # True
list1[1] = 100
print(list2 is list1) # True
print(list1,id(list1)) #[11, 100, 33] 2330938471360
print(list2,id(list2)) #[11, 100, 33] 2330938471360
# 二维列表
list1 = [[11,22,33],[44,55]]
list2 = list1
print(list2 is list1) # True
list1[0][1] = 100
print(list2 is list1) # True
print(list1,id(list1)) #[[11, 100, 33], [44, 55]] 1623859368832
print(list2,id(list2)) #[[11, 100, 33], [44, 55]] 1623859368832
结论:
无论时一维列表还是多维列表,如果使用引用赋值的方式操作,只要通过一个变量修改了列表中的元素,则另一个变量访问的列表也会随着修改
3.2. 列表.copy()
list.copy()相当于拷贝出了一个新的列表空间,当列表为一维列表时为浅拷贝,原列表的的改动对新拷贝的列表没有影响,而当列表为二维列表或多维列表时,仍旧只会拷贝最外层,因此,对原列表的改动会影响备份的列表。
# list.copy()
# 一维列表
list1 = [11,22,33]
list2 = list1.copy()
print(list2 is list1) # False
list1[1] = 100
print(list2 is list1) # False
print(list1,id(list1)) # [11, 100, 33] 2058118525888
print(list2,id(list2)) # [11, 22, 33] 2058120893248
# 二维列表
list1 = [[11,22,33],[44,55]]
list2 = list1.copy()
print(list2 is list1) # False
list1[0][1] = 100
print(list2 is list1) # False
print(list1,id(list1)) #[[11, 100, 33], [44, 55]] 1594975596416
print(list2,id(list2)) #[[11, 100, 33], [44, 55]] 1594972533696
3.3. copy.copy(list)
copy.copy和list.copy功能一样
结论:list.copy和copy.copy(列表) 和切片
一维列表:如果一个变量修改列表中的元素,对另一个列表没有任何影响
二维列表:如果一个变量修改内层列表中的元素,则另一个列表中的元素会随着发生修改
3.4. copy.deepcopy()
copy.deepcopy是深拷贝,相当于完全复制了一个独立的内存空间,原列表的修改对备份的列表没有影响
list1 = [[11,22,33],[44,55]]
list2 = copy.deepcopy(list1)
print(list2 is list1) # False
list1[0][1] = 100
print(list2 is list1) # False
print(list1,id(list1)) #[[11, 100, 33], [44, 55]] 2931563524480
print(list2,id(list2)) #[[11, 22, 33], [44, 55]] 2931566613632
结论:
无论是一维列表的还是多维列表,如果使用copy.deepcopy()的方式操作,通过一个变量修改了列表中的元素,另一个变量访问的列表没有影响
注意:不管是浅拷贝还是深拷贝,都会生成一个新的列表,所有列表的地址都会发生改变