Python:array数组比列表list更高效
大家好,我是科雷!
在Python中,除了我们常用的列表(list),还有一个专门用于处理同类型数据的高效工具array库。相比于列表,array数组在存储和操作同类型数据时更加节省内存、运算速度更快,非常适合处理大量数值型数据。
与列表不同点:
1)array数组只能存储同一类型的数据。
2)array主要用于处理数字(正数或浮点数),或者单个unicode字符,不支持字符串或者其他数据类型,处理的数据类型不像list列表一样丰富。
本文将详细介绍array库的核心功能和常用函数,帮助你快速掌握这个高效数据处理工具。
一、array库基础
array库是 Python 的标准库,无需额外安装,使用前需先导入:
import array
array库的核心是array.array类,用于创建和操作数组。
二、重点函数详解
1.array.array ():创建数组
这是最基础也是最常用的函数,用于创建一个新的数组。
参数说明:
- typecode:必填,单字符字符串,指定数组中元素的类型(见下表)
- initializer:可选,初始化数据,可以是列表、元组或可迭代对象
常用typecode类型:包含整数、浮点数、unicode字符
typecode | 对应的 Python 类型 | 描述(C 语言中的对应类型) | 字节数 | 取值范围(数值类型) |
'b' | int | 有符号字符(signed char) | 1 | -128 到 127 |
'B' | int | 无符号字符(unsigned char) | 1 | 0 到 255 |
'h' | int | 有符号短整数(short) | 2 | -32768 到 32767 |
'H' | int | 无符号短整数(unsigned short) | 2 | 0 到 65535 |
'i' | int | 有符号整数(int) | 2 或 4 | 取决于系统位数 |
'I' | int | 无符号整数(unsigned int) | 2 或 4 | 取决于系统位数 |
'l' | int | 有符号长整数(long) | 4 | -2147483648 到 2147483647 |
'L' | int | 无符号长整数(unsigned long) | 4 | 0 到 4294967295 |
'q' | int | 有符号长 long 整数(long long) | 8 | -9223372036854775808 到 9223372036854775807 |
'Q' | int | 无符号长 long 整数(unsigned long long) | 8 | 0 到 18446744073709551615 |
'f' | float | 单精度浮点数(float) | 4 | 约 ±3.4e±38(6-7 位有效数字) |
'd' | float | 双精度浮点数(double) | 8 | 约 ±1.8e±308(15-17 位有效数字) |
'u' | str(单个字符) | Unicode 字符(wchar_t) | 2 或 4 | 取决于系统的 wchar_t大小(通常为2字节或4字节) |
案例 1:创建不同类型的数组
import array
# 创建整数数组
int_array = array.array('i', [1, 2, 3, 4, 5])
print("整数数组:", int_array) # 输出: array('i', [1, 2, 3, 4, 5])
# 创建浮点数数组
float_array = array.array('d', [1.1, 2.2, 3.3])
print("浮点数数组:", float_array) # 输出: array('d', [1.1, 2.2, 3.3])
# 创建空数组
empty_array = array.array('b')
print("空数组:", empty_array) # 输出: array('b')
# 创建单个unicode字符数组
alist = array.array('u',['a','d'])
print("字符数组:", alist) # 输出: array('u', 'ad')
#创建不符合类型的数组会报错
alist = array.array('i',['a','d'])
#报错:
TypeError: 'str' object cannot be interpreted as an integer
2.append ():添加元素到数组末尾
参数说明:
- x:必填,要添加的元素(必须与数组类型一致)
import array
my_array = array.array('i', [1, 2, 3])
my_array.append(4)
my_array.append(5)
print(my_array) # 输出: array('i', [1, 2, 3, 4, 5])
3.extend ():扩展数组
功能:将另一个数组或可迭代对象的元素添加到当前数组末尾
参数说明:
- iterable:必填,要添加的可迭代对象(元素类型必须与数组一致)
import array
arr1 = array.array('i', [1, 2, 3])
arr2 = array.array('i', [4, 5, 6])
arr1.extend(arr2)
print(arr1) # 输出: array('i', [1, 2, 3, 4, 5, 6])
# 也可以扩展列表(元素类型需一致)
arr1.extend([7, 8, 9])
print(arr1) # 输出: array('i', [1, 2, 3, 4, 5, 6, 7, 8, 9])
4.insert ():插入元素
功能:在指定位置插入一个元素
参数说明:
- i:必填,插入位置的索引
- x:必填,要插入的元素(必须与数组类型一致)
案例:
import array
my_array = array.array('i', [1, 2, 3, 4])
my_array.insert(2, 100) # 在索引2处插入100
print(my_array) # 输出: array('i', [1, 2, 100, 3, 4])
5.pop ():移除并返回元素
功能:移除并返回指定位置的元素,默认移除最后一个元素
参数说明:
- i:可选,要移除元素的索引,默认为 - 1(最后一个元素)
import array
my_array = array.array('i', [10, 20, 30, 40])
# 移除最后一个元素
last = my_array.pop()
print("移除的元素:", last) # 输出: 40
print("操作后数组:", my_array) # 输出: array('i', [10, 20, 30])
# 移除指定索引的元素
first = my_array.pop(0)
print("移除的元素:", first) # 输出: 10
print("操作后数组:", my_array) # 输出: array('i', [20, 30])
6.remove ():移除指定值的元素
功能:移除数组中第一个出现的指定值元素
参数说明:
- x:必填,要移除的元素值
import array
my_array = array.array('i', [10, 20, 30, 20, 40])
my_array.remove(20) # 移除第一个20
print(my_array) # 输出: array('i', [10, 30, 20, 40])
7.fromlist ():从列表添加元素
功能:将列表中的元素添加到数组中
参数说明:
- list:必填,要添加的列表(元素类型必须与数组一致)
import array
my_array = array.array('i', [1, 2, 3])
my_list = [4, 5, 6]
my_array.fromlist(my_list)
print(my_array) # 输出: array('i', [1, 2, 3, 4, 5, 6])
8.tolist ():转换为列表
功能:将数组转换为普通列表
参数说明:无
import array
my_array = array.array('i', [1, 2, 3, 4, 5])
my_list = my_array.tolist()
print("转换后的列表:", my_list) # 输出: [1, 2, 3, 4, 5]
print("列表类型:", type(my_list)) # 输出: <class 'list'>
三、常用函数补充
1.buffer_info ():获取数组内存信息
功能:返回一个元组(address, length),表示数组在内存中的地址和元素个数
import array
my_array = array.array('i', [1, 2, 3, 4, 5])
print(my_array.buffer_info())
# 输出: (4492531344, 5),内存地址每次运行可能不同
2.byteswap ():交换字节顺序
功能:byteswap() 函数用于对数组中每个元素的字节顺序进行反转,这是一个专门用于处理跨平台数据交互的底层操作。仅对多个字节数据有效,单字节类型(如 'b'、'B')的元素没有字节顺序问题,调用 byteswap() 不会产生任何变化。
什么是字节顺序?
字节顺序(又称 "端序")指的是多字节数据在内存中的存储顺序,主要有两种形式:
- 大端序(Big-endian):高位字节存放在低地址(如人类读写习惯,先存高位)
- 小端序(Little-endian):高位字节存放在高地址(与人类读写习惯相反)
不同硬件平台字节顺序可能不同(如 x86 是小端序,某些嵌入式设备是大端序)。
例如,整数 0x1234(十六进制,十进制为 4660)在内存中的存储:
- 大端序:0x12(高位)存放在低地址,0x34(低位)存放在高地址
- 小端序:0x34(低位)存放在低地址,0x12(高位)存放在高地址
import array
# 创建一个2字节有符号整数数组('h'类型)
# 0x1234 表示十进制 4660
arr = array.array('h', [0x1234])
print("原始数组:", arr) # 输出: array('h', [4660])
# 执行字节交换
arr.byteswap()
print("字节交换后:", arr) # 输出: array('h', [873594880])
# 873594880 对应的十六进制是 0x3412,正好是 0x1234 的字节反转
3.count ():统计元素出现次数
功能:返回指定元素在数组中出现的次数
参数说明:
- x:必填,要统计的元素值
import array
my_array = array.array('i', [1, 2, 2, 3, 2, 4])
print("2出现的次数:", my_array.count(2)) # 输出: 3
4.index ():查找元素索引
功能:返回指定元素在数组中第一次出现的索引
参数说明:
- x:必填,要查找的元素值
import array
my_array = array.array('i', [10, 20, 30, 20, 40])
print("20第一次出现的索引:", my_array.index(20)) # 输出: 1
5.reverse ():反转数组
功能:原地反转数组中的元素顺序
import array
my_array = array.array('i', [1, 2, 3, 4, 5])
my_array.reverse()
print("反转后的数组:", my_array) # 输出: array('i', [5, 4, 3, 2, 1])
6.typecode:查看数组类型
功能:属性(非函数),返回数组的类型代码
import array
int_arr = array.array('i', [1, 2, 3])
float_arr = array.array('d', [1.1, 2.2])
print("int_arr类型:", int_arr.typecode) # 输出: i
print("float_arr类型:", float_arr.typecode) # 输出: d
7.itemsize:查看元素字节大小
功能:属性(非函数),返回数组中每个元素的字节大小。实际大小跟上面表中列出的大小不一定相同。
import array
int_arr = array.array('i', [1, 2, 3]) # 'i'类型占2字节
long_arr = array.array('l', [1, 2, 3]) # 'l'类型占4字节
print("int_arr元素大小:", int_arr.itemsize) # 输出: 4
print("long_arr元素大小:", long_arr.itemsize) # 输出: 8
8.clear() :从数组中移除所有元素。
官网说在python3.13版本中增加,由于我本地版本较低,没有试过,看过文章的朋友可以自己试下。
四 array库和list使用对比
1)、内存占用对比:array 更节省空间
列表(list)存储的是对象引用(即使存储基本类型,也会被包装成 Python对象),每个引用额外占用内存;而array直接存储原始二进制数据,仅占用数据本身的空间。
举例:存储 100 万个整数时的内存占用
import array
import sys
# 创建包含100万个整数的列表
list_data = [i for i in range(1000000)]
# 创建相同数据的array('i'类型,2字节整数)
array_data = array.array('i', range(1000000))
# 计算内存占用(近似值)
print(f"列表内存:{sys.getsizeof(list_data) + sum(sys.getsizeof(x) for x in list_data)} 字节")
print(f"array内存:{sys.getsizeof(array_data)} 字节")
结果:列表内存比array内存大了9倍
列表内存:36448724 字节
array内存:4091948 字节
2)、运算速度对比:array 处理数值更快
由于array存储的是连续的原始数据,无需像列表那样处理对象引用和类型检查,因此在批量数值操作时速度更快。
举例:在 100 万个元素中插入一个数字
import array
import time
# 准备数据
n = 1000000
list_data = list(range(n))
array_data = array.array('i', range(n))
# 测试列表累加
start = time.time()
list_data.insert(299333,1)
list_time = time.time() - start
# 测试array累加
start = time.time()
array_data.insert(299333,1)
array_time = time.time() - start
print(f"列表插入时间:{list_time:.6f}秒")
print(f"array插入时间:{array_time:.6f}秒")
print(f"array速度提升:{list_time / array_time:.2f}倍")
结果:
列表插入时间:0.004367秒
array插入时间:0.000105秒
array速度提升:41.63倍
3)适用场景对比:各有优势
场景 | array 优势 | 列表优势 |
数据类型 | 仅同类型数据(适合数值、字符) | 可混合存储任意类型(int、str、对象等) |
内存敏感场景 | 占用空间小,适合大数据集 | 占用空间大,但灵活性高 |
数值运算 | 处理速度快,适合批量计算 | 速度较慢,但支持更多复杂操作 |
功能丰富度 | 方法较少,专注于基础操作 | 内置方法多(如 sort()、count() 等) |
跨平台数据交互 | 支持二进制读写和字节交换(byteswap()) | 需额外序列化(如 pickle) |
五、何时选择 array?
当你需要处理大量同类型数值数据(如传感器读数、统计数据),且关注内存占用和处理速度时,array 是更好的选择。
如果需要存储不同类型数据,或依赖列表的丰富功能(如嵌套、动态类型转换),则应使用列表。
简单来说:array 是 “轻量高效的数值容器”,列表是 “通用灵活的多类型容器”。