1. 模块概述
1.1 什么是array模块
array模块是Python标准库中的一个内置模块,它提供了一种高效存储基本数据类型(如整数、浮点数)的序列结构。与列表(list)相比,array在存储单一数据类型时更加紧凑,内存占用更小,性能更高。
原理:array模块底层使用C语言的数组实现,所有元素必须是相同类型,这使得它在内存中是连续存储的,访问速度更快
1.2 为什么使用array
- 内存效率:存储相同数量的数据时,array比list占用更少内存
- 性能优势:数值计算操作比list更快
- 类型安全:确保数组中所有元素类型一致
- 二进制数据交互:方便与C/C++代码或二进制文件交互
1.3 适用场景举例
- 需要处理大量数值数据
- 内存受限的环境
- 需要与C/C++代码交互
- 处理二进制数据文件
2. 类型码
2.1 类型码表
array模块使用单字符类型码来指定数组中元素的类型。以下是完整的类型码表
| 类型码 | Python 类型 | 最小字节数 | 备注 |
| 'b' | int | 1 | 有符号字节 |
| 'B' | int | 1 | 无符号字节 |
| 'u' | Unicode字符 | 2/4 | Python 3.3+不推荐 |
| 'w' | Unicode字符 | 4 | 推荐替代'u' |
| 'h' | int | 2 | 有符号短整数 |
| 'H' | int | 2 | 无符号短整数 |
| 'i' | int | 2 | 有符号整数 |
| 'I' | int | 2 | 无符号整数 |
| 'l' | int | 4 | 有符号长整数 |
| 'L' | int | 4 | 无符号长整数 |
| 'q' | int | 8 | 有符号长长整数 |
| 'Q' | int | 8 | 无符号长长整数 |
| 'f' | float | 4 | 单精度浮点数 |
| 'd' | float | 8 | 双精度浮点数 |
2.2 类型码选择建议
1. 根据数据范围选择整数类型:
- 小范围整数(0-255):
'B'或'b' - 中等范围整数:
'h'或'H' - 大整数:
'l'、'L'、'q'或'Q'
2. 浮点数选择:
- 一般精度:
'f' - 高精度:
'd'
3. Unicode字符:
- 推荐使用
'w'而非'u',因为'u'将在Python 3.16中移除
3. 创建和初始化array
3.1 array构造函数
class array.array(typecode[, initializer])
参数:
typecode:指定数组元素类型的单字符代码initializer:可选,初始化数组的数据,可以是:- bytes或bytearray对象
- Unicode字符串(仅适用于
'u'或'w'类型码) - 可迭代对象(列表、元组等)
返回值:返回一个新的array对象
3.2 创建array的多种方式
3.2.1 创建空数组
import array# 创建空整数数组
int_arr = array.array('i')
print(int_arr)# 创建空浮点数数组
float_arr = array.array('f')
print(float_arr)
3.2.2 从列表初始化
import array# 从列表创建整数数组
numbers = array.array('i', [1,2,3,4,5])
print(numbers)# 从列表创建浮点数数组
temps = array.array('f', [23.5,27.8,19.2])
print(temps)
3.2.3 从bytes/bytearray初始化
import array# 从bytes创建数组
data = b'\x01\x00\x00\x00\x02\x00\x00\x00' # 两个32位整数
int_arr = array.array('i', data)
print(int_arr)# 从bytearray创建
byte_data = bytearray(b'\x01\x02\x03\x04')
byte_arr = array.array('B', byte_data)
print(byte_arr)
3.2.4 从Unicode字符串初始化
import array# 创建Unicode字符数组
text = array.array('w', '你好Python')
print(text)
3.3 注意事项
- 类型一致性:所有元素必须是相同类型
- 类型转换:初始化时会自动尝试将元素转换为指定类型
- 错误处理:类型不匹配会引发TypeError
- 内存分配:数组大小固定后,内存连续分配
4. array基本操作
4.1 访问元素
array支持所有序列操作,包括索引、切片等。
import arraynumbers = array.array('i', [10, 20, 30, 40, 50])# 索引访问
print(numbers[0]) # 10
print(numbers[-1]) # 50# 切片操作
print(numbers[1:3]) # array('i', [20, 30])
print(numbers[:3]) # array('i', [10, 20, 30])
print(numbers[3:]) # array('i', [40, 50])# 修改元素
numbers[0] = 100
print(numbers) # array('i', [100, 20, 30, 40, 50])
4.2 添加元素
4.2.1 append()方法
功能:在数组末尾添加一个元素
import arrayarr = array.array('d')
arr.append(3.14)
arr.append(2.71)
print(arr) # array('f', [3.14, 2.71])
4.2.2 extend()方法
功能:从可迭代对象添加多个元素
import arrayarr = array.array('i', [1, 2, 3])
arr.extend([4, 5, 6])
print(arr) # array('i', [1, 2, 3, 4, 5, 6])# 也可以扩展另一个array,但类型必须匹配
other = array.array('i', [7, 8])
arr.extend(other)
print(arr) # array('i', [1, 2, 3, 4, 5, 6, 7, 8])
4.2.3 insert()方法
功能:在指定位置插入元素
import arrayarr = array.array('B', [1, 2, 4, 5])
arr.insert(2, 3) # 在索引2处插入3
print(arr) # array('B', [1, 2, 3, 4, 5])
4.3 删除元素
4.3.1 pop()方法
功能:移除并返回指定位置的元素
import arrayarr = array.array('i', [10, 20, 30, 40])
print(arr.pop()) # 40 (默认移除最后一个)
print(arr.pop(0)) # 10 (移除第一个)
print(arr) # array('i', [20, 30])
4.3.2 remove()方法
功能:移除第一个匹配的元素
import arrayarr = array.array('i', [1, 2, 3, 2, 4])
arr.remove(2) # 移除第一个2
print(arr) # array('i', [1, 3, 2, 4])
4.3.3 clear()方法
功能:清空数组(Python 3.13+)
import arrayarr = array.array('d', [1.1, 2.2, 3.3])
arr.clear()
print(arr) # array('d')
import arrayarr = array.array('d', [1.1, 2.2, 3.3])
arr = array.array('d') # 创建一个新的空数组
print(arr) # array('d')arr = array.array('d', [1.1, 2.2, 3.3])
del arr[:] # 删除数组中的所有元素
print(arr) # array('d')arr = array.array('d', [1.1, 2.2, 3.3])
while len(arr) > 0:arr.pop() # 逐个删除元素
print(arr) # array('d')arr = array.array('d', [1.1, 2.2, 3.3])
arr[:] = [] # 使用切片赋值清空数组
print(arr) # array('d')
4.4 其他常用操作
4.4.1 count()方法
功能:统计元素出现次数
import arrayarr = array.array('i', [1, 2, 2, 3, 2, 4])
print(arr.count(2)) # 3
4.4.2 index()方法
功能:查找元素首次出现的位置
import arrayarr = array.array('i', [10, 20, 30, 20, 40])
print(arr.index(20)) # 输出 1,因为 20 第一次出现在索引 1
print(arr.index(20, 2)) # 输出 3,从索引 2 开始查找 20,第一次出现在索引 3
4.4.3 reverse()方法
功能:反转数组
import arrayarr = array.array('h', [1, 2, 3, 4])
arr.reverse()
print(arr) # array('h', [4, 3, 2, 1])
5. 数组与二进制数据交互
5.1 tobytes()和frombytes()
5.1.1 tobytes()
功能:将数组转换为字节表示
import arrayarr = array.array('i', [1, 2, 3])
byte_data = arr.tobytes()
print(byte_data) # b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'
5.1.2 frombytes()
功能:从字节数据重建数组
import arrayarr = array.array('i', [1, 2, 3])
byte_data = arr.tobytes()new_arr = array.array('i')
new_arr.frombytes(byte_data)
print(new_arr) # array('i', [1, 2, 3])
5.2 tofile()和fromfile()
5.2.1 tofile()
功能:将数组写入文件
import arrayarr = array.array('d', [1.1, 2.2, 3.3])
with open('data.bin', 'wb') as f:arr.tofile(f)
5.2.2 fromfile()
功能:从文件读取数组数据
import arraynew_arr = array.array('d')
with open('data.bin', 'rb') as f:new_arr.fromfile(f, 3) # 读取3个元素print(new_arr) # array('d', [1.1, 2.2, 3.3])
5.3 byteswap()
功能:交换字节顺序(大小端转换)
import arrayarr = array.array('h', [1, 256]) # 0x0001, 0x0100
print(arr.tobytes()) # b'\x01\x00\x00\x01'
arr.byteswap()
print(arr.tobytes()) # b'\x00\x01\x01\x00'
print(arr) # array('h', [256, 1])
6. 特性和性能考虑
6.1 缓冲区接口
array实现了缓冲区协议,可以高效地与其它支持缓冲区接口的对象交互
import arrayarr = array.array('i', [1, 2, 3, 4, 5])# 使用 memoryview 访问缓冲区
mv = memoryview(arr)
print(mv[1:3].tolist()) # [2, 3]# 修改数据会反映到原数组
mv[2] = 99
print(arr) # array('i', [1, 2, 99, 4, 5])
6.2 性能比较
表2: array与list性能比较(操作100万个元素)
| 操作 | array('i') | list | 优势比 |
| 创建时间 | 0.05s | 0.12s | 2.4x |
| 内存占用 | 4MB | 8MB | 2x |
| 遍历速度 | 0.03s | 0.05s | 1.7x |
| 求和速度 | 0.02s | 0.08s | 4x |
6.3 类型转换
import array# array转list
arr = array.array('f', [1.1, 2.2, 3.3])
lst = arr.tolist()
print(lst) # [1.1, 2.2, 3.3]# list转array
new_arr = array.array('f', lst)
print(new_arr) # array('f', [1.1, 2.2, 3.3])
7. 应用举例
7.1 处理大型数值数据集示例
import array
import random
import time# 生成100万个随机数
start = time.time()
data = array.array('d', (random.random() for _ in range(1_000_000)))
print(f"生成array耗时:{time.time() - start:.3f}秒")# 计算平均值
start = time.time()
mean = sum(data) / len(data)
print(f"计算平均值耗时:{time.time() - start:.4f}秒")
print(f"平均值:{mean:.4f}")# 内存占用比较
import syslist_data = list(data)
print(f"array内存占用:{sys.getsizeof(data) / 1_000_000:.2f}MB")
print(f"list内存占用:{sys.getsizeof(list_data) / 1_000_000:.2f}MB")
7.2 二进制文件处理示例
import arraydef save_sensor_data(filename, data):"""保存传感器数据到二进制文件"""arr = array.array('H', data)with open(filename, 'wb') as f:arr.tofile(f)def load_sensor_data(filename, count):"""从二进制文件加载传感器数据"""arr = array.array('H')with open(filename, 'rb') as f:arr.fromfile(f, count)return arr# 模拟传感器数据
sensor_data = [100, 105, 110, 115, 120, 118, 116, 114]# 保存并加载数据
save_sensor_data('sensor.bin', sensor_data)
loaded_data = load_sensor_data('sensor.bin', len(sensor_data))
print("加载的数据:", loaded_data.tolist())
7.3 与NumPy交互示例
虽然array模块功能有限,但可以轻松转换为NumPy数组进行高级数值计算:
import array
import numpy as np# 创建array
arr = array.array('d', [1.1, 2.2, 3.3, 4.4])# 转换为NumPy数组
np_arr = np.array(arr)
print("NumPy数组:", np_arr)# 执行NumPy操作
print("平方:", np.square(np_arr))
print("平均值:", np.mean(np_arr))# 转换回array
new_arr = array.array('d', np_arr.tolist())
print("转换回array:", new_arr)
| 类型码 | C 类型 | Python 类型 | 最小字节数 | 备注 |
|---|---|---|---|---|
'b' |
signed char | int | 1 | 有符号字节 |
'B' |
unsigned char | int | 1 | 无符号字节 |
'u' |
wchar_t | Unicode字符 | 2/4 | 平台相关,Python 3.3+不推荐 |
'w' |
Py_UCS4 | Unicode字符 | 4 | 推荐替代'u' |
'h' |
signed short | int | 2 | 有符号短整数 |
'H' |
unsigned short | int | 2 | 无符号短整数 |
'i' |
signed int | int | 2 | 有符号整数 |
'I' |
unsigned int | int | 2 | 无符号整数 |
'l' |
signed long | int | 4 | 有符号长整数 |
'L' |
unsigned long | int | 4 | 无符号长整数 |
'q' |
long long | int | 8 | 有符号长长整数 |
'Q' |
unsigned long long | int | 8 | 无符号长长整数 |
'f' |
float | float | 4 | 单精度浮点数 |
'd' |
double | float | 8 | 双精度浮点数 |
2.2 类型码选择建议
-
根据数据范围选择整数类型:
- 小范围整数(0-255):
'B'或'b' - 中等范围整数:
'h'或'H' - 大整数:
'l'、'L'、'q'或'Q' -
浮点数选择:
- 一般精度:
'f' - 高精度:
'd' -
Unicode字符:
- 推荐使用
'w'而非'u',因为'u'将在Python 3.16中移除
3. 创建和初始化array
3.1 array构造函数
原型:
class array.array(typecode[, initializer])
参数:
typecode:指定数组元素类型的单字符代码initializer:可选,初始化数组的数据,可以是:- bytes或bytearray对象
- Unicode字符串(仅适用于
'u'或'w'类型码) - 可迭代对象(列表、元组等)
返回值:返回一个新的array对象
3.2 创建array的多种方式
3.2.1 创建空数组
import array
# 创建空整数数组
int_arr = array.array('i')
print(int_arr) # array('i')
# 创建空浮点数数组
float_arr = array.array('f')
print(float_arr) # array('f')
3.2.2 从列表初始化
# 从列表创建整数数组
numbers = array.array('i', [1, 2, 3, 4, 5])
print(numbers) # array('i', [1, 2, 3, 4, 5])
# 从列表创建浮点数数组
temps = array.array('f', [23.5, 27.8, 19.2])
print(temps) # array('f', [23.5, 27.8, 19.2])
3.2.3 从bytes/bytearray初始化
# 从bytes创建数组
data = b'\x01\x00\x00\x00\x02\x00\x00\x00' # 两个32位整数
int_arr = array.array('i', data)
print(int_arr) # array('i', [1, 2])
# 从bytearray创建
byte_data = bytearray(b'\x01\x02\x03\x04')
byte_arr = array.array('B', byte_data)
print(byte_arr) # array('B', [1, 2, 3, 4])
3.2.4 从Unicode字符串初始化
# 创建Unicode字符数组
text = array.array('w', '你好Python')
print(text) # array('w', '你好Python')
3.3 注意事项
- 类型一致性:所有元素必须是相同类型
- 类型转换:初始化时会自动尝试将元素转换为指定类型
- 错误处理:类型不匹配会引发TypeError
- 内存分配:数组大小固定后,内存连续分配
4. array基本操作
4.1 访问元素
array支持所有序列操作,包括索引、切片等。
numbers = array.array('i', [10, 20, 30, 40, 50])
# 索引访问
print(numbers[0]) # 10
print(numbers[-1]) # 50
# 切片操作
print(numbers[1:3]) # array('i', [20, 30])
print(numbers[:3]) # array('i', [10, 20, 30])
print(numbers[3:]) # array('i', [40, 50])
# 修改元素
numbers[0] = 100
print(numbers) # array('i', [100, 20, 30, 40, 50])
4.2 添加元素
4.2.1 append()方法
功能:在数组末尾添加一个元素
arr = array.array('f')
arr.append(3.14)
arr.append(2.71)
print(arr) # array('f', [3.14, 2.71])
4.2.2 extend()方法
功能:从可迭代对象添加多个元素
arr = array.array('i', [1, 2, 3])
arr.extend([4, 5, 6])
print(arr) # array('i', [1, 2, 3, 4, 5, 6])
# 也可以扩展另一个array,但类型必须匹配
other = array.array('i', [7, 8])
arr.extend(other)
print(arr) # array('i', [1, 2, 3, 4, 5, 6, 7, 8])
4.2.3 insert()方法
功能:在指定位置插入元素
arr = array.array('B', [1, 2, 4, 5])
arr.insert(2, 3) # 在索引2处插入3
print(arr) # array('B', [1, 2, 3, 4, 5])
4.3 删除元素
4.3.1 pop()方法
功能:移除并返回指定位置的元素
arr = array.array('i', [10, 20, 30, 40])
print(arr.pop()) # 40 (默认移除最后一个)
print(arr.pop(0)) # 10 (移除第一个)
print(arr) # array('i', [20, 30])
4.3.2 remove()方法
功能:移除第一个匹配的元素
arr = array.array('i', [1, 2, 3, 2, 4])
arr.remove(2) # 移除第一个2
print(arr) # array('i', [1, 3, 2, 4])
4.3.3 clear()方法
功能:清空数组(Python 3.13+)
arr = array.array('d', [1.1, 2.2, 3.3])
arr.clear()
print(arr) # array('d')
4.4 其他常用操作
4.4.1 count()方法
功能:统计元素出现次数
arr = array.array('i', [1, 2, 2, 3, 2, 4])
print(arr.count(2)) # 3
4.4.2 index()方法
功能:查找元素首次出现的位置
arr = array.array('i', [10, 20, 30, 20, 40])
print(arr.index(20)) # 1
print(arr.index(20, 2)) # 3 (从索引2开始查找)
4.4.3 reverse()方法
功能:反转数组
arr = array.array('h', [1, 2, 3, 4])
arr.reverse()
print(arr) # array('h', [4, 3, 2, 1])
5. 数组与二进制数据交互
5.1 tobytes()和frombytes()
5.1.1 tobytes()
功能:将数组转换为字节表示
arr = array.array('i', [1, 2, 3])
byte_data = arr.tobytes()
print(byte_data) # b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'
5.1.2 frombytes()
功能:从字节数据重建数组
new_arr = array.array('i')
new_arr.frombytes(byte_data)
print(new_arr) # array('i', [1, 2, 3])
5.2 tofile()和fromfile()
5.2.1 tofile()
功能:将数组写入文件
arr = array.array('d', [1.1, 2.2, 3.3])
with open('data.bin', 'wb') as f:
arr.tofile(f)
5.2.2 fromfile()
功能:从文件读取数组数据
new_arr = array.array('d')
with open('data.bin', 'rb') as f:
new_arr.fromfile(f, 3) # 读取3个元素
print(new_arr) # array('d', [1.1, 2.2, 3.3])
5.3 byteswap()
功能:交换字节顺序(大小端转换)
arr = array.array('h', [1, 256]) # 0x0001, 0x0100
print(arr.tobytes()) # b'\x01\x00\x00\x01'
arr.byteswap()
print(arr.tobytes()) # b'\x00\x01\x01\x00'
print(arr) # array('h', [256, 1])
6. 特性和性能考虑
6.1 缓冲区接口
array实现了缓冲区协议,可以高效地与其它支持缓冲区接口的对象交互。
arr = array.array('i', [1, 2, 3, 4, 5])
# 使用memoryview访问缓冲区
mv = memoryview(arr)
print(mv[1:3].tolist()) # [2, 3]
# 修改数据会反映到原数组
mv[2] = 99
print(arr) # array('i', [1, 2, 99, 4, 5])
6.2 性能比较
表2: array与list性能比较(操作100万个元素)
| 操作 | array('i') | list | 优势比 |
|---|---|---|---|
| 创建时间 | 0.05s | 0.12s | 2.4x |
| 内存占用 | 4MB | 8MB | 2x |
| 遍历速度 | 0.03s | 0.05s | 1.7x |
| 求和速度 | 0.02s | 0.08s | 4x |
6.3 类型转换
# array转list
arr = array.array('f', [1.1, 2.2, 3.3])
lst = arr.tolist()
print(lst) # [1.1, 2.2, 3.3]
# list转array
new_arr = array.array('f', lst)
print(new_arr) # array('f', [1.1, 2.2, 3.3])
7. 应用举例
7.1 处理大型数值数据集示例
import array
import random
import time
# 生成100万个随机数
start = time.time()
data = array.array('d', (random.random() for _ inrange(1_000_000)))
print(f"生成array耗时: {time.time()-start:.3f}秒")
# 计算平均值
start = time.time()
mean = sum(data) / len(data)
print(f"计算平均值耗时: {time.time()-start:.4f}秒")
print(f"平均值: {mean:.4f}")
# 内存占用比较
import sys
list_data = list(data)
print(f"array内存占用: {sys.getsizeof(data)/1_000_000:.2f}MB")
print(f"list内存占用: {sys.getsizeof(list_data)/1_000_000:.2f}MB")
7.2 二进制文件处理示例
import array
defsave_sensor_data(filename, data):
"""保存传感器数据到二进制文件"""
arr = array.array('H', data)
withopen(filename, 'wb') as f:
arr.tofile(f)
defload_sensor_data(filename, count):
"""从二进制文件加载传感器数据"""
arr = array.array('H')
withopen(filename, 'rb') as f:
arr.fromfile(f, count)
return arr
# 模拟传感器数据
sensor_data = [100, 105, 110, 115, 120, 118, 116, 114]
# 保存并加载数据
save_sensor_data('sensor.bin', sensor_data)
loaded_data = load_sensor_data('sensor.bin', len(sensor_data))
print("加载的数据:", loaded_data.tolist())
7.3 与NumPy交互示例
虽然array模块功能有限,但可以轻松转换为NumPy数组进行高级数值计算:
import array
import numpy as np
# 创建array
arr = array.array('d', [1.1, 2.2, 3.3, 4.4])
# 转换为NumPy数组
np_arr = np.array(arr)
print("NumPy数组:", np_arr)
# 执行NumPy操作
print("平方:", np.square(np_arr))
print("平均值:", np.mean(np_arr))
# 转换回array
new_arr = array.array('d', np_arr.tolist())
print("转换回array:", new_arr)
8. 知识图谱
9. 学习路线
-
基础阶段:
- 理解array与list的区别
- 掌握类型码的选择
- 学习基本的创建和操作方法
-
中级阶段:
- 掌握二进制数据交互
- 学习文件读写操作
- 理解缓冲区协议
-
高级阶段:
- 性能优化技巧
- 与NumPy等库的交互
- 实际项目应用
-
专家阶段:
- 深入理解内存布局
- 与C/C++扩展交互
- 自定义高效数据结构
10. 总结
10.1 核心要点
- array是高效存储单一类型数据的序列结构
- 通过类型码指定元素类型,影响内存占用和性能
- 支持所有基本序列操作,以及二进制数据交互
- 内存连续分配,访问速度快,适合数值计算
10.2 实践建议
- 选择最合适的类型码以节省内存
- 批量操作(extend, fromlist)比循环append更高效
- 使用缓冲区协议实现零拷贝数据共享
- 对于复杂数值计算,考虑转换为NumPy数组
10.3 注意事项
- 类型必须一致,否则会引发TypeError
- 'u'类型码已被弃用,应使用'w'
- 文件操作要注意字节顺序(大小端问题)
- 与list相比,array不支持多维结构和混合类型
通过合理使用array模块,可以在处理大量数值数据时获得显著的内存和性能优势,特别是在内存受限或需要高性能计算的场景中。
更新日期:2025-07-25
交流讨论:欢迎在评论区留言!
作者简介:ICodeWR,专注于科技与编程的全栈开发者,定期分享实用编程技巧和项目实战经验。持续学习、适应变化、记录点滴、复盘反思、成长进步。
重要提示:本文主要是记录自己的学习与实践过程,所提内容或者观点仅代表个人意见,只是我以为的,不代表完全正确,不喜请勿关注。
