本来第一次看《流畅的python》觉得这部分没用,就跳过去,后面又出现,回头看还是一知半解,查了诸多资料,好像有一点明白了,立下帖子。
1、memoryview
memoryview() 函数返回给定参数的内存查看对象(memory view)。
所谓内存查看对象,是指对支持缓冲区协议的数据进行包装,在不需要复制对象基础上允许Python代码访问。
可以简单理解为就是对内存地址的直接访问。
memoryview可以对对象进行索引或者切片,不过切片的返回结果为一个子memoryview对象:
import array
# 创建一个signed short 类型数组,占2bytes
nums = array.array('h', list(range(-2, 3)))
mem = memoryview(nums)
print(len(mem)) # 5
print(mem[0]) # -2
print(mem[1:4]) # <memory at 0x000002B56F01E4C8>
mem相当于nums在内存中的表示形式,但是属于不同的对象:
>>>mem is nums
False
>>>mem == nums
True
同样,memoryview对象有tolist方法可以转换为列表:
>>>mem.tolist()
[-2, -1, 0, 1, 2]
2、memoryview.cast
memoryview.cast会把同一块内存里的内容打包成一个全新的memoryview对象。
>>>mem_oct = mem.cast('B')
>>>mem.nbytes == mem_oct.nbytes
True
>>>mem.itemsize == mem_oct.itemsize
False
在转换以后,所占字节数保持不变,但是单个元素的所占字节由原来的2个变成1个(‘h’ --> ‘B’)。
Type code | C Type | Python Type | Minimum size in bytes |
---|---|---|---|
‘c’ | char | character | 1 |
‘b’ | signed char | int | 1 |
‘B’ | unsigned char | int | 1 |
‘u’ | Py_UNICODE | Unicode character | 2 (see note) |
‘h’ | signed short | int | 2 |
‘H’ | unsigned short | int | 2 |
‘i’ | signed int | int | 2 |
‘I’ | unsigned int | long | 2 |
‘l’ | signed long | int | 4 |
‘L’ | unsigned long | long | 4 |
‘f’ | float | float | 4 |
‘d’ | double | float | 8 |
将mem_oct转换为list,你会发现mem_oct居然包含10个元素:
>>>mem_oct.tolist()
[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
所包含的元素也很奇怪,这个就涉及到存储的一些知识,为了将将符号位和数值域统一处理,同时加法和减法也可以统一处理,计算机系统中数值一律用补码来表示和存储。
以-2为例,初始设置其数据类型为占用两个字节的’long’,其原码是1000 0000 0000 0010,而在计算机存储的是1111 1111 1111 1110,其低八位为254,高8位为255,所以知道mem_oct前两个元素从哪里来了吧。
对于2来说,原码为0000 0000 0000 0010,补码为其本身(正数的补码与原码一致),所以转换后为2,0。
欢迎关注我的微信公众号