《流畅的Python》示例 2-21 memoryview

本文通过《流畅的Python》示例2-21解析memoryview如何通过修改字节改变数组值。首先介绍了array模块的类型码参数,然后详细解释了如何从unsigned short转换到unsigned char,并通过具体步骤展示如何在内存中进行操作,导致原始unsigned short类型的值发生改变,以此理解memoryview的功能和原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在看这个示例的时候对于如何通过修改字节来改变原来数组里的值,产生了一些混淆,在此记录。

在研究这个示例前需要了解下 array 创建数组所用的类型码参数,以下列出了所能支持的类型码及其存储尺寸:

表格来自 array --- 高效的数值数组 — Python 3.9.6 文档

接下来看示例代码,第一步创建数组:

numbers = array.array('h', [-2, -1, 0, 1, 2])

这一步创建的数组所用的类型码为 h 即有符号短整型(unsigned short),以两个字节表示,而一个字节存储的是八位,也就是说这一步数组所存储的五个数,在内存里是这样的(左侧为低位,右侧为高位):

# -2
0111 1111 1111 1111
# -1 
1111 1111 1111 1111
# 0
0000 0000 0000 0000
# 1
1000 0000 0000 0000
# 2
0100 0000 0000 0000

对于 unsigned short 类型,其最高位存储符号,1为负数,0为正数,为负数时,其值是反着算的,可以根据上面 -1 和 -2 的表示方式来很好理解,-1 作为最大的负数,以全 1 来表示。

当我们执行 memoryview 函数时,实际上直接拿到了这些数在内存里的存储内容,例如第三步:

memv_oct = memv.cast('B')

这一步将 memv 里的内容转换为 B 类型,即无符号字符,内存中的数据实际上没有变化,变化的是解读这些内容的方式。在 B 类型中,一个字节表示一个 int 类型的数,不带符号。

也就是说,原来由两个字节表示的 unsigned short 类型,将会被视作两个 unsigned char,也就是两个 python 中的 int 类型:

# -2 0111 1111 1111 1111 被拆分为 254 和 255
# 254
0111 1111
# 255
1111 1111

# -1 1111 1111 1111 1111 被拆分为两个 255
# 255
1111 1111
# 255
1111 1111

# 0 0000 0000 0000 0000 被拆分为两个 0
# 0
0000 0000
# 0
0000 0000

# 1 1000 0000 0000 0000 被拆分为 1 和 0
# 1
1000 0000
# 0
0000 0000

# 2 0100 0000 0000 0000 被拆分为 2 和 0
# 2
0100 0000
# 0
0000 0000

因此有了第四步的结果:

memv_oct.tolist()
# [254, 255, 255, 255, 0, 0, 1, 0, 2, 0]

5 个数变成了 10 个数,但此时内存中的内容并没有变化,只是理解这些内容的方式变了而已。

而在第五步操作时,对内存进行了操作,即对此时的 memv_oct 的第 6 个数(索引从 0 开始)赋值为 4:

memv_otc[5] = 4

即第 6 个数 0 变成了 4,在内存中则为:

# 0 -> 4
0000 0000 -> 0010 0000

也就是原本表示第 3 个 unsigned short 类型的两个字节中,高位字节变成了 0010 0000

那么当回到 unsigned short 类型时,原本第三个是 0(0000 0000 0000 0000)变成了 1024(0000 0000 0010 0000)

也就是第六步的结果:

numbers
# array('h', [-2, -1, 1024, 1, 2])

这个例子里面没有直接对 numbers 进行操作,而是直接对 numbers 在内存中存储的字节进行了精确操作。

 我的Github:Cheereus (FanToolMan) (github.com)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

范图曼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值