# 如果我们需要一个只包含数字的列表,那么array.array比list更高效,因为数组在背后存的并不是int对象,而是数字的机器翻译,也就是字节表示.
# 数组支持所有跟可变序列相关的操作,包括.pop .insert和.extend.另外,数组还提供从文件读取和存入文件的更快的方法,如.frombytes和.tofile
# Python数组跟C语言数组一样精简.创建数组需要一个类型码,这个类型码用来表示在底层的C语言应该存放怎样的数据类型.
# 比如b类型码代表的是有符号的字符(signed char),因此array('b')创建出的数组就只能存放一个字节大小的整数,范围从-128到127,这样在序列很大的时候,我们能节省很多空间.
# Python不会允许你的数组里存放除指定类型之外的数据.
from array import array
from random import random
# 利用一个可迭代对象来建立一个双精度浮点数数组(类型码是'd'),这里使用的是生成器表达式
floats = array('d', (random() for i in range(10**7)))
print(floats[-1]) # 0.9775667988984832
fp = open('float.bin', mode='wb')
floats.tofile(fp) # 把数组存入一个二进制文件
fp.close()
floats_2 = array('d')
fp_2 = open('float.bin', mode='rb')
floats_2.frombytes(fp_2.read()) # 从二进制文件中读取数组
# floats_2.fromfile(fp_2, 10**7) # 这样也可以
fp_2.close()
print(floats_2[-1]) # 0.9775667988984832
print(floats == floats_2) # True
# 用array.fromfile从一个二进制文件里读取1000万个双精度浮点数只需要0.1秒,这比从文本文件里读取的速度要快60倍,因为后者会使用内置的float方法把每一行文字转换成浮点数
# 另外,使用array.tofile写入到二进制文件,比以每行一个浮点数的方式把所有数字写入到文本文件要快7倍.
# 另外,1000万个这样的数在二进制文件里只占用80 000 000个字节(每个浮点数占用8个字节,不需要任何额外空间),如果是文本文件的话,我们需要181 515 739个字节.
# 内存视图 memoryview
# memoryview是一个内置类,它能让用户在不复制内容的情况下操作同一个数组的不同切片
# 内存视图其实是泛化和去数学化的NumPy数组.它让你在不需要复制内容的前提下,在数据结构之间共享内存.其中数据结构可以是任何形式,比如PIL图片,SQLite数据库和NumPy数组.
numbers = array('h', [-2, -1, 0, 1, 2])
# 1.利用含有5个短整型有符号整数的数组(类型码是'h')创建一个memoryview
memv = memoryview(numbers)
# 2.memoryview里的5个元素和数组里的没有区别
print(len(memv)) # 5
print(memv[0]) # -2
# 3.创建一个memv_oct,这一次是把memv里的内容转换成'B'类型,也就是无符号字符.
memv_oct = memv.cast('B')
# 4.以列表的形式查看memv_oct内容
print(memv_oct.tolist()) # [254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
# 5.把位于位置5的字节赋值成4
memv_oct[5] = 4
# 6.因为我们把占2个字节的整数的高位字节改成了4,既00000100 00000000,所以这个0变成了1024
print(numbers) # array('h', [-2, -1, 1024, 1, 2])