拓冰建站拓冰建站
首页 / 资讯中心 / 正文

MicroPython array 模块完全指南:数值型数组的类型码、缓冲协议与内存高效用法

嵌入式语言运行时编程语言解释器编译器物联网系统编程【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址https://gitcode.com/gh_mirrors/mi/micropython点击查看免费下载导读array是 MicroPython 内置的数值型数组模块它用 C 语言原生的连续内存块存储同类型元素相比 Python 列表list在内存占用上显著更小、访问速度更快非常适合微控制器这类内存受限constrained systems环境下的数据采集、传感器读数缓冲、二进制协议组包/解析等场景。本文以 docs/library/array.rst 为骨架结合源码实现与官方测试用例系统讲解array的类型码typecode、构造方式、读写方法、切片语义、缓冲协议互操作以及运算符与比较规则帮助你写出内存友好且行为正确的 MicroPython 数组代码。模块概览与 CPythonarray的对应关系array模块在 MicroPython 中与 CPython 标准库同名模块相对应__name__为array对外仅暴露一个工厂类array。从源码看模块本身非常精简py/modarray.c 中模块全局表只注册了array一个符号并通过MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_array, mp_module_array)注册为可扩展模块而类型array的完整行为构造、打印、迭代、下标、缓冲等全部实现在 py/objarray.c 的mp_type_array类型对象中并与bytearray、memoryview共享大量实现代码。支持的格式类型码与官方文档一致共 12 种类型码C 类型字节大小有符号bsigned char1是Bunsigned char1否hsigned short2是Hunsigned short2否isigned int4是Iunsigned int4否lsigned long4是Lunsigned long4否qsigned long long8是Qunsigned long long8否ffloat单精度4依赖浮点支持ddouble双精度8依赖浮点支持上述字节大小依据 py/binary.c 中mp_binary_get_size()的native 对齐分支b/B为 1 字节h/H为sizeof(short)i/I为sizeof(int)l/L为 4 字节q/Q为 8 字节。其中f、d两个浮点类型码取决于固件是否启用浮点支持MicroPython 存在MICROPY_FLOAT_IMPL_NONE的无浮点构建若编译配置未开启浮点使用f/d会失败。q/Q是否可用还受目标平台整数宽度影响在纯 32 位平台上按 8 字节布局存储。注意MicroPython 的l/L固定为 4 字节而非某些平台上 Clong的 8 字节这是与 CPython 的一个细微差异点。构造array(typecode, [iterable])array构造函数的原型为array(typecode, [iterable])第一个参数typecode必填为上述类型码字符字符串第二个参数iterable可选提供初始元素省略时创建空数组。从实现看array_make_new()py/objarray.c在只传一个参数时直接分配一个长度为 0 的空数组传入两个参数时调用array_construct()py/objarray.c完成构造。array_construct()有一条特殊的“原始拷贝”raw copy路径当初始值是一个bytes或bytearray对象且其缓冲区长度是元素大小的整数倍时MicroPython 直接memcpy底层字节不做逐元素转换——这意味着array(h, b\x01\x00\x02\x00)这类写法是允许的并且与字节序无关原样复制。官方测试 tests/basics/array_construct.py 明确验证了从bytes/bytearray的原始拷贝行为。常见构造示例from array import array # 空数组 empty array(h) print(len(empty)) # 0 # 从列表构造 a array(B, [1, 2, 3]) print(a, len(a)) # array(B, [1, 2, 3]) 3 # 从元组构造 b array(b, (1, 2)) # 从 bytes 原始拷贝字节序中立 c array(h, b\x01\x00\x02\x00) # 2 个元素原样复制 # 从其他 array 转换 d array(H, array(b, [1, 2])) # 从 bytearray 构造 e array(i, bytearray(4)) # 1 个 4 字节 int 元素值为 0array_construct()中mp_obj_len_maybe(initializer)会先尝试取得初始值的长度以便一次性预分配底层缓冲区py/objarray.c对于已知长度的可迭代对象如列表、元组、另一个数组可以避免多次扩容重分配这是写内存高效代码时值得利用的特性。核心方法append与extendappend(val)在数组末尾追加一个新元素并自动扩容返回None。底层实现在 py/objarray.c当空闲容量free耗尽时会以“每次额外多分配 8 个元素”的策略m_renew重新分配内存即 amortized 扩容避免频繁 realloc然后通过mp_binary_set_val_array()把 Python 值按类型码编码写入。因此append会做隐式类型转换array(B).append(300)之类的越界值会被按该类型的 C 语义截断或抛错。extend(iterable)把可迭代对象中的所有元素追加到数组末尾返回None等价于原地拼接。底层array_extend()py/objarray.c有一个与 CPython 不同的扩展行为任何实现了缓冲协议的对象如bytes、bytearray、另一个array都会走“整块拷贝”快速路径——直接把对方的原始缓冲区按自身元素大小分割后memcpy进来不具备缓冲协议的对象如列表、生成器则退回逐元素迭代。官方测试 tests/basics/array_add.py 验证了extend接受 array、list 和生成器表达式三种输入。a array(I, [1]) a.extend(array(I, [5])) # 数组 a.extend([6, 7]) # 列表 a.extend(i for i in (8, 9)) # 生成器 print(a) # array(I, [1, 5, 6, 7, 8, 9])下标访问与切片语义__getitem__(index)——a[index]当index为整数时返回该位置元素的 Python 标量值负数索引从末尾倒数越界抛出IndexError。当index为切片时返回一个新的array类型码与源数组相同。底层由array_subscr()py/objarray.c实现切片读取会新建数组并用memcpy拷贝元素区域切片步长仅支持 1即None其他步长会抛NotImplementedError。特别说明__getitem__等特殊方法不能以a.__getitem__(0)的形式直接调用会失败也不会出现在a.__dict__中但a[0]语法正常可用。这是 MicroPython 为省内存而对特殊方法做特殊处理的普遍设计。a array(h, [10, 20, 30, 40]) print(a[0]) # 10 print(a[-1]) # 40负数索引从末尾数 print(a[1:3]) # array(h, [20, 30])切片返回新数组__setitem__(index, value)——a[index] valueindex为整数时把value按类型码编码后写入该位置负数索引同样支持越界抛IndexError。index为切片时value必须是一个array或兼容对象右侧元素的类型码必须与左侧兼容否则抛ValueError源码中的compat_error分支见 py/objarray.c切片的赋值/替换支持改变数组长度MP_PY_ARRAY_SLICE_ASSIGN配置开启时。a array(B, [1, 2, 3, 4]) a[0] 9 print(a) # array(B, [9, 2, 3, 4]) a[1:3] array(B, [7, 8, 9]) print(a) # array(B, [9, 7, 8, 9, 4])切片赋值可改变长度__len__()——len(a)返回数组的元素个数不是字节数。底层由array_unary_op()中的MP_UNARY_OP_LEN分支直接返回内部len字段py/objarray.c是一个 O(1) 操作。同样的特殊方法限制依然适用a.__len__()直接调用会失败len(a)正常工作。拼接运算与a other__add__返回一个新的array内容为两数组按顺序拼接。底层MP_BINARY_OP_ADD分支py/objarray.c在分配新缓冲区后调用mp_seq_cat拼接一个 MicroPython 对 CPython 的扩展是右侧操作数可以是任何有缓冲协议的对象如bytes而不限定必须是array。a other__iadd__原地拼接语义完全等价于extend(other)py/objarray.c返回原对象本身。a1 array(I, [1]) a2 array(I, [2]) print(a1 a2) # array(I, [1, 2])新对象 a1 array(I, [3, 4]) print(a1) # array(I, [1, 3, 4])原地修改表示形式__repr__str(a)与repr(a)返回形如array(type, [elements])的字符串其中type是类型码字母elements是逗号分隔的元素列表。底层array_print()py/objarray.c逐元素调用mp_binary_get_val_array解码并打印。空数组的表示为array(h)无方括号部分。print(repr(array(b, [1, 2, 3]))) # array(b, [1, 2, 3]) print(array(h)) # array(h)同样地__repr__也不能以a.__repr__()直接调用但str(a)/repr(a)均可。缓冲协议与memoryview、bytes的零拷贝互操作文档明确说明array对象实现了缓冲协议buffer protocol整个数组的内容可以作为原始字节直接访问例如通过memoryview或任何使用该协议的接口。这是array在嵌入式场景最有价值的特性之一底层由array_get_buffer()py/objarray.c暴露buf指向元素内存的指针与len字节长度 元素个数 × 元素大小并报告typecode。因此你可以把array直接传给bytes()、memoryview()、struct.unpack()、串口/UART 写入、网络socket.send()等接受缓冲协议对象的 API实现零拷贝传输。用memoryview包装后可以按任意切片查看同一块内存而无需复制memoryview对象内部持有指向原数组缓冲的指针见 py/objarray.c 对 memoryview 复用 array 实现的设计注释只要原数组仍被引用就不会被 GC 回收。a array(H, [0x1234, 0x5678]) mv memoryview(a) # 零拷贝视图 print(mv[0]) # 0x1234按元素访问 raw bytes(a) # 转成 4 个原始字节 print(len(raw)) # 4官方测试 tests/basics/array1.py 也验证了bytes(array(b, ...)) babc以及array(b, [...]) babc这类基于缓冲内容的比较行为。比较运算规则array支持相等与大小比较规则如下对应 py/objarray.c 的typecode_for_comparison()与array_binary_op()相等比较/!只要两侧的类型码“兼容”大小写形式相同如b与B、h与H就按底层字节内容比较与bytes等有缓冲协议的对象也可以比较。浮点类型码f/d不参与按字节比较NaN 永不等于自身此时会抛NotImplementedError。大小比较、、、仅限无符号整数类型码B/H/I/L/Q且按字节序列做字典序比较有符号类型码或不兼容类型码的大小比较抛NotImplementedError。官方的 tests/basics/array1.py 对b/h/i/l/q及其大写形式的两两相等性、以及 tests/basics/array1.py 对无符号类型码的大小比较都有覆盖。print(array(b, [1, 2]) array(B, [1, 2])) # True有符号/无符号兼容 print(array(B, [1, 1]) array(B, [1, 2])) # True无符号字典序比较迭代与成员测试array是可直接迭代的对象MP_TYPE_FLAG_ITER_IS_GETITER迭代器实现在 py/objarray.c按元素逐个返回 Python 标量可用于for循环、sum()、列表推导等。成员测试in仅对bytearray支持子串搜索对一般array若右侧是整数或浮点数会抛NotImplementedError其他情况返回Falsepy/objarray.c。bool(array)依据元素个数判断真假空数组为False非空为TrueMP_UNARY_OP_BOOL见 tests/basics/array1.py。a array(B, [1, 2, 3]) for x in a: print(x) # 1 2 3 print(bool(array(i))) # False print(bool(array(i, [1]))) # True使用建议与注意事项内存优先用array而非list以array(B)存储 1000 个传感器读数仅占约 1 KB 连续内存而 Pythonlist因每个元素都是独立对象对象头 指针 数据通常要多消耗数倍内存在 RAM 只有几十 KB 的 MCU 上差异巨大。优先用扩展性好的extend整块拷贝向数组追加大量数据时extend(bytes/bytearray/array)走底层memcpy快路径比逐元素append更高效预知元素总数时可先用array(typecode, [0]*n)或从已知长度对象构造避免中途反复扩容。用好缓冲协议实现零拷贝 I/O采集完一批数据后直接用memoryview(a)或直接传入bytes(a)即可把array内容交给UART.write()、socket.send()、struct.unpack()等接口无需手工逐元素转换。注意类型码差异MicroPython 的l/L固定 4 字节f/d依赖固件浮点支持q/Q受平台位宽影响。跨固件移植时以当前固件的实际行为为准。特殊方法不可直接调用__getitem__/__setitem__/__len__/__add__/__iadd__/__repr__均不能以a.__xxx__()形式直接调用会失败且不出现在__dict__中必须使用对应的运算符或内建函数语法。延伸阅读模块入口与注册py/modarray.carray/bytearray/memoryview共享的核心实现py/objarray.c类型码字节大小与二进制编解码py/binary.c官方行为测试tests/basics/array1.py、tests/basics/array_construct.py、tests/basics/array_construct_endian.py、tests/basics/array_add.py官方 API 文档docs/library/array.rst赞分享嵌入式语言运行时编程语言解释器编译器物联网系统编程【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址https://gitcode.com/gh_mirrors/mi/micropython点击查看免费下载相关推荐CPython array 模块深入解析类型化数值数组的高效内存表示与完整 API 指南CPython array 模块深入解析类型化数值数组的高效内存表示与完整 API 指南 array 模块标准库内置于 CPython提供一种以紧凑、连续编程语言语言运行时解释器标准库PyArrow 内存数据模型完全指南数据类型、Schema、Array、RecordBatch 与 Table 的构建、切片与互操作PyArrow 内存数据模型完全指南数据类型、Schema、Array、RecordBatch 与 Table 的构建、切片与互操作 本篇基于 Apache大数据数据分析数据工程序列化终极指南如何使用Wire协议缓冲区构建跨平台高效数据模型终极指南如何使用Wire协议缓冲区构建跨平台高效数据模型 Wire是一个强大的协议缓冲区工具专为Android、Kotlin、Swift和Java平台设计序列化代码生成后端上一篇告别兼容性困扰macOS-VirtualBox全版本适配测试6.1至最新版下一篇Android-PickerView 终极解析WheelView滚轮核心机制深度揭秘创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门