(笔记)Python可变和不可变数据类型——猜想

我不是资深程序员,不敢说一定就是这样,但是至少自己想明白了,所以写在这里备忘。

由列表深、浅拷贝所想到的

python中,变量名和实际数据是分离的,一个变量名可以在不同时间指向不同数据

id()函数返回的是变量名所指向的那个数据在python内存池(不知道这样说是否恰当)中的id,比如下列代码

>>> a = 1
>>> id(a)
1727161440
>>> id(1)
1727161440
>>>

1和a的id是一样的

接下来是重头戏

列表在python官方解释中,说是“可变数据类型”,也就是说,值改变了,但是id不会变,这是怎么一回事呢?

猜想:列表是一块内存区域,这块内存区域用来指向其他数据,说白了就是下图:

a = [0, 1, 2]

接下来是验证猜想阶段

test_1

定义下面这样的列表:

a = [[1, 2, 3], 2, 3]

猜想其存储方式为:

根据上述猜测,更改a[0][0]和a[1],那么id(a)和id(a[0])不应该变化,id(a[0][0])和id(a[1])应该变化

>>> a=[[1,2,3],2,3]
>>> id(a)
6834776
>>> id(a[0])
8176384
>>> id(a[0][0])
1727161440
>>> id(a[1])
1727161456
>>> a[0][0] = 0
>>> a[1] = 0
>>> id(a)
6834776
>>> id(a[0])
8176384
>>> id(a[0][0])
1727161424
>>> id(a[1])
1727161424
>>>

结果正确

test_2

深拷贝和浅拷贝

浅拷贝:

>>> a=[1,2,3]
>>> b=[4,5,6]
>>> b=a
>>> b[0]=100
>>> a
[100, 2, 3]
>>> b
[100, 2, 3]
>>>

浅拷贝实际上将变量名直接指向了另一个变量名所指向的列表内存空间,也就是下图:

(虚线是更改后的指针)

那么以后操作b,也就实际上是在a所指向的列表上进行操作了。显然,再访问a时,a会发生变化,这一般是我们所不希望看到的

深拷贝

>>> a=[1,2,3]
>>> b=[4,5,6]
>>> for i in range(len(a)):
...     b[i] = a[i]
...
>>> b[0] = 100
>>> a
[1, 2, 3]
>>> b
[100, 2, 3]
>>>

要想实现深拷贝,那就应该先创建列表的内存空间,然后更改该内存空间,而不是更改列表名,如下图:

(虚线是更改后的指针)

test_3

关于append()的问题

>>> a=[[1,2,3],2,3]
>>> b=[]
>>> for i in range(len(a)):
...     b.append(a[i])
...
>>> b[0][0]=100
>>> a
[[100, 2, 3], 2, 3]
>>> b
[[100, 2, 3], 2, 3]
>>>

append()也是操作 变量名所指向的实际数据块,并没有创建副本。上述代码中,append()直接将a[0]所指向的那个 列表 的内存块加在了b的后面,从而导致了浅拷贝

类似的还有

>>> a=[[1,2,3],2,3]
>>> b=[]
>>> for i in a:
...     b.append(i)
...
>>> b[0][0]=100
>>> a
[[100, 2, 3], 2, 3]
>>> b
[[100, 2, 3], 2, 3]
>>>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值