MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.
#include <string.h>
#include <assert.h>
// 引入MicroPython运行时和对象类型定义
#include "py/runtime.h"
#include "py/builtin.h"
#include "py/objtype.h"
#include "py/objstr.h"
/**
* 判断一个对象是否为字典或有序字典
* @param o 需要判断的MicroPython对象
* @return 如果是字典或有序字典则返回true,否则返回false
*/
bool mp_obj_is_dict_or_ordereddict(mp_obj_t o) {
return mp_obj_is_obj(o) && MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type, make_new) == mp_obj_dict_make_new;
}
// 定义一个空字典对象,用于初始化和作为默认值
const mp_obj_dict_t mp_const_empty_dict_obj = {
.base = {
.type = &mp_type_dict }, // 基础类型设置为字典类型
.map = {
.all_keys_are_qstrs = 0, // 所有键是否为qstr(快速字符串)类型
.is_fixed = 1, // 是否固定,不可修改
.is_ordered = 1, // 是否有序,保持插入顺序
.used = 0, // 已使用的元素数量
.alloc = 0, // 分配的元素数量
.table = NULL // 字典存储的数组,初始为NULL
}
};
// 字典更新函数,用于处理字典更新操作
static mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
// 字典迭代器辅助函数,用于遍历字典中的元素
static mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) {
size_t max = dict->map.alloc; // 获取字典分配的槽位数量
mp_map_t *map = &dict->map; // 获取字典的map结构体
size_t i = *cur; // 当前迭代位置
for (; i < max; i++) {
// 遍历槽位
if (mp_map_slot_is_filled(map, i)) {
// 如果槽位被填充(即有元素)
*cur = i + 1; // 更新迭代位置
return &(map->table[i]); // 返回当前槽位的元素
}
}
assert(map->used == 0 || i == max); // 确保所有元素都已遍历
return NULL; // 如果没有更多元素,返回NULL
}
// 字典的打印函数,用于格式化输出字典内容
static void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); // 转换对象指针为字典结构体指针
bool first = true; // 是否为第一个元素,用于控制输出格式
const char *item_separator = ", "; // 元素分隔符
const char *key_separator = ": "; // 键值分隔符
// 根据打印类型(如JSON或普通字符串)调整分隔符
if (!(MICROPY_PY_JSON && kind == PRINT_JSON)) {
kind = PRINT_REPR;
} else {
#if MICROPY_PY_JSON_SEPARATORS
item_separator = MP_PRINT_GET_EXT(print)->item_separator;
key_separator = MP_PRINT_GET_EXT(print)->key_separator;
#endif
}
// 如果是有序字典,打印类型名称
if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) {
mp_printf(print, "%q(", self->base.type->name);
}
mp_print_str(print, "{"); // 打印左大括号
size_t cur = 0; // 初始化迭代位置
mp_map_elem_t *next = NULL; // 当前迭代到的元素
while ((next = dict_iter_next(self, &cur)) != NULL) {
// 遍历字典
if (!first) {
// 如果不是第一个元素,打印分隔符
mp_print_str(print, item_separator);
}
first = false; // 更新标志位
// 根据是否为JSON打印格式,决定是否为键添加引号
bool add_quote = MICROPY_PY_JSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key);
if (add_quote) {
mp_print_str(print, "\"");
}
mp_obj_print_helper(print, next->key, kind); // 打印键
if (add_quote) {
mp_print_str(print, "\"");
}
mp_print_str(print, key_separator); // 打印键值分隔符
mp_obj_print_helper(print, next->value, kind); // 打印值
}
mp_print_str(print, "}");
if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) {
mp_print_str(print, ")");
}
}
// 创建新字典的函数
mp_obj_t mp_obj_dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_obj_t dict_out = mp_obj_new_dict(0); // 创建一个新字典对象
mp_obj_dict_t *dict = MP_OBJ_TO_PTR(dict_out); // 转换对象指针为字典结构体指针
dict->base.type = type; // 设置字典的基础类型
// 如果是有序字典,设置相应的标志位
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
if (type == &mp_type_ordereddict) {
dict->map.is_ordered = 1;
}
#endif
// 如果有参数传递,执行更新操作
if (n_args > 0 || n_kw > 0) {
mp_obj_t args2[2] = {
dict_out, args[0]}; // 构造参数数组,args[0]是必须存在的
mp_map_t kwargs; // 创建一个临时的参数映射
mp_map_init_fixed_table(&kwargs, n_kw, args + n_args); // 初始化参数映射
dict_update(n_args + 1, args2, &kwargs); // 调用更新函数,注意参数数量检查
}
return dict_out; // 返回新创建的字典对象
}
// 字典单目操作函数,处理如bool()和len()等操作
static mp_obj_t dict_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); // 转换对象指针为字典结构体指针
switch (op) {
case MP_UNARY_OP_BOOL: // 判断字典是否为空
return mp_obj_new_bool(self->map.used != 0);
case MP_UNARY_OP_LEN: // 获取字典长度(元素数量)
return MP_OBJ_NEW_SMALL_INT(self->map.used);
#if MICROPY_PY_SYS_GETSIZEOF
case MP_UNARY_OP_SIZEOF: // 获取字典对象占用的内存大小
size_t sz = sizeof(*self) + sizeof(*self->map.table) * self->map.alloc;
return MP_OBJ_NEW_SMALL_INT(sz);
#endif
default:
return MP_OBJ_NULL; // 操作不支持
}
}
// 字典二目操作函数,处理如in、==、|、or等操作
static mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_dict_t *o = MP_OBJ_TO_PTR(lhs_in); // 转换左侧对象指针为字典结构体指针
switch (op) {
case MP_BINARY_OP_CONTAINS: // 判断字典是否包含某个键
mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);
return mp_obj_new_bool(elem != NULL);
case MP_BINARY_OP_EQUAL: // 判断两个字典是否相等
// 如果是有序字典的情况,需要特殊处理
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
if (MP_UNLIKELY(mp_obj_is_type(lhs_in, &mp_type_ordereddict) && mp_obj_is_type(rhs_in, &mp_type_ordereddict))) {
// 同时遍历两个字典,比较键和值
mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in);
size_t c1 = 0, c2 = 0;
mp_map_elem_t *e1 = dict_iter_next(o, &c1), *e2 = dict_iter_next(rhs, &c2);
for (; e1 != NULL && e2 != NULL; e1 = dict_iter_next(o, &c1), e2 = dict_iter_next(rhs, &c2)) {
if (!mp_obj_equal(e1->key, e2->key) || !mp_obj_equal(e1->value, e2->value)) {
return mp_const_false;
}
}
return e1 == NULL && e2 == NULL ?mp_const_true : mp_const_false;
}
#endif
// 如果右侧对象也是字典,比较它们的键值对
if (mp_obj_is_type(rhs_in, &mp_type_dict)) {
mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in);
if (o->map.used != rhs->map.used) {
return mp_const_false;
}
size_t cur = 0;
mp_map_elem_t *next = NULL;
while ((next = dict_iter_next(o, &cur)) != NULL) {
mp_map_elem_t *elem = mp_map_lookup(&rhs->map, next->key, MP_MAP_LOOKUP);
if (elem == NULL || !mp_obj_equal(next->value, elem->value)) {
return mp_const_false;
}
}
return mp_const_true;
} else {
// 字典与其它类型的对象不相等
return mp_const_false;
}
#if MICROPY_CPYTHON_COMPAT
case MP_BINARY_OP_INPLACE_OR:
case MP_BINARY_OP_OR: // 对字典进行合并操作
if (op == MP_BINARY_OP_OR) {
lhs_in = mp_obj_dict_copy(lhs_in); // 复制字典,以便后续修改
}
mp_obj_t dicts[2] = {
lhs_in, rhs_in}; // 构造包含两个字典的数组
dict_update(2, dicts, (mp_map_t *)&mp_const_empty_map); // 更新字典,合并内容
return lhs_in; // 返回左侧字典对象
}
#endif
default:
// 操作不支持
return MP_OBJ_NULL;
}
}
// 字典项的获取函数,用于实现字典的索引操作
mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) {
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); // 转换对象指针为字典结构体指针
mp_map_elem_t *elem = mp_map_lookup(&self->map,