Python变量地址和拷贝相关问题总结

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()的方式操作,通过一个变量修改了列表中的元素,另一个变量访问的列表没有影响

注意:不管是浅拷贝还是深拷贝,都会生成一个新的列表,所有列表的地址都会发生改变

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值