MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.
microPython Python最小内核源码解析
这段代码是MicroPython的内部实现,涉及数组(array)、字节数组(bytearray)和内存视图(memoryview)对象的创建、操作和管理。代码中包含了对象的构造函数、打印函数、迭代器、索引操作、缓冲区获取等方法的实现。这些方法为MicroPython提供了强大的数据结构和内存管理能力,使得在资源受限的微控制器上也能进行高效的数据处理。
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include "py/runtime.h"
#include "py/binary.h"
#include "py/objstr.h"
#include "py/objarray.h"
// 判断是否支持某些MicroPython内置模块
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
// 关于memoryview对象:我们希望尽可能重用array的代码,并保持memoryview对象的大小为4个词,以便它适合1个GC块。
// 此外,memoryview必须保留指向缓冲区基础的指针,以便如果原始父对象不再存在,缓冲区不会被GC回收(我们假设所有可memoryview的对象都返回指向GC块开头的指针)。
// 鉴于上述限制,我们进行以下操作:
// - 如果缓冲区是读写的,则设置typecode高位(否则为只读)
// - free是memoryview中第一个元素的偏移量
// - len是元素长度
// - items指向原始缓冲区的开始
// 请注意,我们不处理原始缓冲区可能由于原始父对象的大小调整而改变大小的情况。
// 如果启用了memoryview,则定义TYPECODE_MASK
#define TYPECODE_MASK (0x7f)
// memview_offset是memoryview中第一个元素的偏移量
#define memview_offset free
// memview_offset_max是memview_offset的最大值
#define memview_offset_max ((1LL << MP_OBJ_ARRAY_FREE_SIZE_BITS) - 1)
#else
// 如果没有启用memoryview,则使(& TYPECODE_MASK)成为一个空操作以捕获错误
#define TYPECODE_MASK (~(size_t)0)
// 如果没有启用memoryview,则不应访问memview_offset,因此不定义以捕获错误
#endif
// 声明函数
static mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf);
static mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
static mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in);
static mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
/******************************************************************************/
// array对象的实现
// 如果启用了bytearray或array模块
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
// 打印array对象
static void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
// kind参数被忽略
mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
// 根据typecode打印不同的信息
if (o->typecode == BYTEARRAY_TYPECODE) {
mp_print_str(print, "bytearray(b");
mp_str_print_quoted(print, o->items, o->len, true);
} else {
mp_printf(print, "array('%c'", o->typecode);
if (o->len > 0) {
mp_print_str(print, ", [");
for (size_t i = 0; i < o->len; i++) {
if (i > 0) {
mp_print_str(print, ", ");
}
// 使用typecode打印元素
mp_obj_print_helper(print, mp_binary_get_val_array(o->typecode, o->items, i), PRINT_REPR);
}
mp_print_str(print, "]");
}
}
mp_print_str(print, ")");
}
#endif
// 如果启用了bytearray或array模块
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
// 创建新的array对象
static mp_obj_array_t *array_new(char typecode, size_t n) {
// 根据typecode计算每个元素的大小
int typecode_size = mp_binary_get_size('@', typecode, NULL);
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
// 根据typecode设置对象类型
#if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY
o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
#elif MICROPY_PY_BUILTINS_BYTEARRAY
o->base.type = &mp_type_bytearray;
#else
o->base.type = &mp_type_array;
#endif
o->typecode = typecode;
o->free = 0; // 初始化free为0
o->len = n; // 设置元素数量
// 分配内存存储元素
o->items = m_new(byte, typecode_size * o->len);
return o;
}
#endif
// 如果启用了bytearray或array模块
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
// 根据给定对象构造array对象
static mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
// 如果是bytearray,可以从任何支持缓冲协议的对象中初始化
// 其他数组只能从bytes和bytearray对象中初始化
mp_buffer_info_t bufinfo;
// 检查是否可以从缓冲区中读取数据
if (((MICROPY_PY_BUILTINS_BYTEARRAY
&& typecode == BYTEARRAY_TYPECODE)
|| (MICROPY_PY_ARRAY
&& (mp_obj_is_type(initializer, &mp_type_bytes)
|| (MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(initializer, &mp_type_bytearray)))))
&& mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {
// 从原始字节构造数组
// 向下取整len以使其成为sz的倍数(CPython会抛出错误)
size_t sz = mp_binary_get_size('@', typecode, NULL);
size_t len = bufinfo.len