Python中创建支持索引读写的整数/浮点数类列表对象的最快方法
嘿,针对你这个问题——要做一个能快速执行索引获取和索引修改的类列表对象,而且专门存整数/浮点数这种简单类型,核心思路就是要避开Python普通对象带来的额外开销,毕竟咱们要的是“最快”嘛。
先明确你的核心需求:两个基础操作obj[index]和obj[index] = value,那直接用Python底层优化过的数组结构肯定是最优解,下面给你列几个最靠谱的方案:
1. 用标准库array模块(首推:平衡速度、轻量、无依赖)
array.array是Python自带的模块,专门用来存储同类型的数值,底层是C实现的连续数组,比普通列表更紧凑,读写速度几乎和原生C数组看齐,而且天然支持你要的两个索引操作,完全不需要自己写额外逻辑。
举个例子:
import array # 'i'代表存储int类型,可选的类型码还有:'d'(双精度浮点数)、'f'(单精度浮点数) num_list = array.array('i', [10, 20, 30, 40]) # 获取指定索引的元素 print(num_list[1]) # 输出20 # 修改指定索引的元素 num_list[2] = 300 print(num_list) # 输出array('i', [10, 20, 300, 40])
这个方案的优势在于:标准库自带不用额外装包,速度快,内存占用比普通列表小(因为不用包装每个数值成Python对象),完美匹配你的需求。
2. 用NumPy数组(适合需要后续数值运算的场景)
如果你的类列表对象之后还要做数值计算(比如加减乘除、矩阵操作),那NumPy的ndarray绝对是更快的选择——它的索引操作是高度优化的C实现,比普通列表快几个数量级,而且同样天然支持索引读写。
示例代码:
import numpy as np # 指定dtype为float64(双精度浮点数),确保存储的是你需要的数值类型 num_arr = np.array([1.2, 3.4, 5.6], dtype=np.float64) # 获取元素 print(num_arr[0]) # 输出1.2 # 修改元素 num_arr[1] = 9.9 print(num_arr) # 输出array([1.2, 9.9, 5.6])
要是单纯只做索引读写,它的速度和array.array差不多,但如果有后续数值运算需求,NumPy的优势就非常明显了。
3. 自定义类(不推荐,除非有特殊定制需求)
如果一定要自己写类来实现,那得尽量减少Python层面的开销,比如用__slots__减少内存占用,或者直接继承collections.abc.MutableSequence但只实现必要的方法,但这种方式肯定比上面两种慢——因为每次索引操作都要经过Python的方法调用,多了一层开销。
举个最简化的自定义实现(本质还是依赖array.array来提速):
import array from collections.abc import MutableSequence class NumList(MutableSequence): __slots__ = ('_data',) # 限制属性,减少内存开销 def __init__(self, init_data): # 内部用array.array存储,借它的底层速度 self._data = array.array('d', init_data) def __getitem__(self, idx): return self._data[idx] def __setitem__(self, idx, value): self._data[idx] = value def __len__(self): return len(self._data) # 继承MutableSequence必须实现的方法,要是用不上可以留空但别报错 def insert(self, idx, value): self._data.insert(idx, value) def __delitem__(self, idx): del self._data[idx]
但说实话,这种自定义方式完全没必要,因为直接用array.array已经能满足需求,还更快更省心。
为啥你之前看的帖子方案没用?
你提到之前的帖子解决不了问题,大概率是那些方案要么用了普通列表包装(有Python对象开销)、要么用字典模拟索引(速度慢)、要么是只读的生成器(不支持修改)——这些都不符合“最快+支持读写索引”的要求。而上面的array.array和NumPy数组都是直接操作底层同类型数值,完全踩中你的需求点。
总结一下:单纯要索引读写,选array.array;要数值运算,选NumPy数组。这俩都是目前最快的方案了。
内容的提问来源于stack exchange,提问作者ArthurQ

