MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.
microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
python编程示例系列 python编程示例系列二
python的Web神器Streamlit
代码是一个元组对象和其迭代器的实现,包括创建、打印、比较、索引和迭代等操作。代码中包含了丰富的注释,解释了每个函数和结构体的作用以及它们的工作方式。这些注释有助于理解代码的逻辑和实现细节。
#include <string.h>
#include <assert.h>
#include "py/objtuple.h"
#include "py/runtime.h"
// 检查对象是否兼容元组类型,允许元组、具名元组、属性元组
#define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter)
/******************************************************************************/
/* 元组对象实现 */
/**
* 打印元组对象,支持JSON格式输出。
* @param print 打印函数指针。
* @param o_in 要打印的元组对象。
* @param kind 打印类型,例如普通的打印或JSON格式。
*/
void mp_obj_tuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in);
const char *item_separator = ", "; // 元素分隔符
if (MICROPY_PY_JSON && kind == PRINT_JSON) {
mp_print_str(print, "["); // JSON格式下,使用方括号包围元组
// 如果定义了自定义的分隔符,则使用该分隔符
#if MICROPY_PY_JSON_SEPARATORS
item_separator = MP_PRINT_GET_EXT(print)->item_separator;
#endif
} else {
mp_print_str(print, "("); // 普通打印使用圆括号包围元组
kind = PRINT_REPR; // 使用表示法打印
}
for (size_t i = 0; i < o->len; i++) {
// 遍历元组中的每个元素
if (i > 0) {
mp_print_str(print, item_separator); // 打印元素之间的分隔符
}
mp_obj_print_helper(print, o->items[i], kind); // 递归打印当前元素
}
// 根据打印类型,添加相应的结束符号
if (MICROPY_PY_JSON && kind == PRINT_JSON) {
mp_print_str(print, "]");
} else {
if (o->len == 1) {
mp_print_str(print, ",");
}
mp_print_str(print, ")");
}
}
/**
* 创建一个新的元组对象。
* @param type_in 元组类型。
* @param n_args 参数数量。
* @param n_kw 关键字参数数量。
* @param args 参数列表。
* @return 新的元组对象。
*/
static mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
(void)type_in; // 忽略传入的类型参数
mp_arg_check_num(n_args, n_kw, 0, 1, false); // 检查参数数量和关键字参数数量
// 根据参数数量决定如何创建元组
switch (n_args) {
case 0:
// 创建一个空元组
return mp_const_empty_tuple;
case 1:
default: {
// 一个参数,一个可迭代对象,我们根据它创建一个新的元组
if (mp_obj_is_type(args[0], &mp_type_tuple)) {
// 如果参数已经是元组类型,则直接返回
return args[0];
}
// TODO 优化已知迭代器长度的情况
size_t alloc = 4; // 初始分配空间大小
size_t len = 0; // 当前元素数量
mp_obj_t *items = m_new(mp_obj_t, alloc); // 分配内存
mp_obj_t iterable = mp_getiter(args[0], NULL); // 获取迭代器
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
// 遍历迭代器
if (len >= alloc) {
// 如果当前元素数量达到分配的内存大小
items = m_renew(mp_obj_t, items, alloc, alloc * 2); // 扩大内存空间
alloc *= 2; // 内存空间翻倍
}
items[len++] = item; // 保存元素
}
mp_obj_t tuple = mp_obj_new_tuple(len, items); // 创建新的元组对象
m_del(mp_obj_t, items, alloc); // 释放分配的内存
return tuple; // 返回新创建的元组对象
}
}
}
// 比较操作辅助函数
static mp_obj_t tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) {
// 检查自身是否为元组兼容对象
mp_check_self(mp_obj_is_tuple_compatible(self_in));
const mp_obj_type_t *another_type = mp_obj_get_type(another_in); // 获取另一个对象的类型
mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); // 获取自身对象指针
// 如果另一个对象不是元组类型,则尝试转换为元组
if (MP_OBJ_TYPE_GET_SLOT_OR_NULL(another_type, iter) != mp_obj_tuple_getiter) {
// 如果是用户自定义的子类,则通过铸型转换为元组
another_in = mp_obj_cast_to_native_base(another_in, MP_OBJ_FROM_PTR(&mp_type_tuple));
if (another_in == MP_OBJ_NULL) {
return MP_OBJ_NULL; // 如果转换失败,则返回空对象
}
}
mp_obj_tuple_t *another = MP_OBJ_TO_PTR(another_in); // 获取另一个对象的指针
// 调用序列比较函数,返回比较结果
return mp_obj_new_bool(mp_seq_cmp_objs(op, self->items, self->len, another->items, another->len));
}
/**
* 处理一元操作符。
* @param op 操作符类型。
* @param self_in 操作数对象。
* @return 操作结果。
*/
mp_obj_t mp_obj_tuple_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); // 获取元组对象指针
switch (op) {
case MP_UNARY_OP_BOOL: // 布尔运算
return mp_obj_new_bool(self->len != 0); // 根据元组长度返回布尔值
case MP_UNARY_OP_HASH: {
// 哈希运算
// 以空元组的指针作为哈希起始值
mp_int_t hash = (mp_int_t)mp_const_empty_tuple;
for (size_t i = 0; i < self->len; i++) {
// 累加每个元素的哈希值
hash += MP_OBJ_SMALL_INT_VALUE(mp_unary_op(MP_UNARY_OP_HASH, self->items[i]));
}
return MP_OBJ_NEW_SMALL_INT(hash); // 返回计算得到的哈希值
}
case MP_UNARY_OP_LEN: // 长度运算
return MP_OBJ_NEW_SMALL_INT(self->len); // 返回元组长度
default:
return MP_OBJ_NULL; // 如果操作符不支持,则返回空对象
}
}
/**
* 处理二元操作符。
* @param op 操作符类型。
* @param lhs 左边操作数。
* @param rhs 右边操作数。
* @return 操作结果。
*/
mp_obj_t mp_obj_tuple_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
mp_obj_tuple_t *o = MP_OBJ_TO_PTR(lhs); // 获取左边操作数的元组对象指针
// 根据操作符类型执行不同的操作
switch (op) {
case MP_BINARY_OP_ADD: // 加法运算,合并两个元组
case MP_BINARY_OP_INPLACE_ADD: {
// 检查右边操作数是否为元组类型
if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(rhs)), MP_OBJ_FROM_PTR(&mp_type_tuple))) {
return MP_OBJ_NULL; // 如果不是,则返回空对象
}
mp_obj_tuple_t *p = MP_OBJ_TO_PTR(rhs); // 获取右边操作数的元组对象指针
// 创建一个新的元组,长度为两个元组长度之和
mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len + p->len, NULL));
// 将两个元组的元素复制到新元组中
mp_seq_cat(s->items, o->items, o->len, p->items, p->len, mp_obj_t);
return MP_OBJ_FROM_PTR(s); // 返回新创建的元组对象
}
case MP_BINARY_OP_MULTIPLY: // 乘法运算,重复元组
case MP_BINARY_OP_INPLACE_MULTIPLY: {
mp_int_t n;
// 尝试获取右边操作数的整数值
if (!mp_obj_get_int_maybe(rhs, &n)) {
return MP_OBJ_NULL; // 如果失败,则返回空对象
}
if (n <= 0) {
return mp_const_empty_tuple; // 如果重复次数非正,则返回空元组
}
// 创建一个新的元组,长度为元组长度乘以重复次数
mp_obj_tuple_t *s = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->len * n, NULL));
// 复制元组元素到新元组中
mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items);
return MP_OBJ_FROM_PTR(s); // 返回新创建的元组对象
}
case MP_BINARY_OP_EQUAL: // 相等比较
case MP_BINARY_OP_LESS: // 小于比较
case MP_BINARY_OP_LESS_EQUAL: // 小于等于比较
case MP_BINARY_OP_MORE: // 大于比较
case MP_BINARY_OP_MORE_EQUAL: // 大于等于比较
return tuple_cmp_helper(op, lhs, rhs); // 调用辅助函数进行比较
default:
return MP_OBJ_NULL; // 如果操作符不支持,则返回空对象
}
}
/**
* 处理元组的索引操作。
* @param self_in 元组对象。
* @param index 索引对象。
* @param value 赋值对象,如果是MP_OBJ_SENTINEL则表示读取操作。
* @return 索引操作的结果。
*/
mp_obj_t mp_obj_tuple_subscr(mp_obj_t sel