microPython的源码解析之 objtuple.c

本文主要探讨MicroPython的实现,重点解析元组对象的创建、比较、索引和迭代等操作。通过源码分析,帮助读者理解Python解析器的核心逻辑,涉及C语言实现,适合嵌入式硬件和单片机开发的Python爱好者。
摘要由CSDN通过智能技术生成

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
  • 17
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

openwin_top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值