microPython的源码解析之 objtype.c

本文深入解析MicroPython的objtype.c源码,重点探讨对象和类型管理、实例创建、属性访问、特殊方法支持、操作符重载等功能,帮助读者理解Python解析器的核心实现逻辑,适合嵌入式硬件和单片机开发中的Python编程。
摘要由CSDN通过智能技术生成

MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.


microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
python编程示例系列 python编程示例系列二
python的Web神器Streamlit


这段代码是MicroPython的实现,主要功能是提供Python编程语言的核心功能和对象模型。具体来说,它包括以下几个方面:

对象和类型管理:代码中定义了如何创建和管理对象类型(mp_obj_type_t),包括类的创建、实例化、以及类的属性和方法的存储与访问。

实例创建:通过mp_obj_new_instance函数,可以创建一个新的对象实例,包括初始化其属性和方法。

属性和方法访问:提供了mp_obj_class_lookup、mp_obj_instance_load_attr、mp_obj_instance_store_attr等函数,用于在对象实例中查找、读取和设置属性。

特殊方法支持:实现了Python中的特殊方法,如__new__、initstrrepr、__call__等,这些方法对应于对象的创建、字符串表示、调用等行为。

操作符重载:通过instance_unary_op和instance_binary_op函数,实现了对一元和二元操作符的重载,允许自定义对象支持各种算术和比较操作。

迭代器和序列化:提供了mp_obj_instance_getiter和instance_subscr函数,支持迭代器协议和序列化访问,如列表索引和切片操作。

类型检查和继承:实现了mp_obj_is_subclass和mp_obj_is_instance函数,用于检查对象的类型和继承关系。

静态方法和类方法:通过mp_type_staticmethod和mp_type_classmethod,支持静态方法和类方法的定义和调用。

错误处理:在执行过程中,如果遇到不支持的操作或属性访问错误,会抛出相应的异常。

整体而言,这段代码是MicroPython虚拟机的一部分,负责实现Python语言的核心特性,使得在资源受限的微控制器上也能运行Python代码。

#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>

// 打印调试信息
#if MICROPY_DEBUG_VERBOSE
#define DEBUG_PRINT (1)
#define DEBUG_printf DEBUG_printf
#else
#define DEBUG_PRINT (0)
#define DEBUG_printf(...) (void)0
#endif

// 启用特殊的访问器
#define ENABLE_SPECIAL_ACCESSORS (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY)

// 原生类型基类的实例计数
static int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) {
   
    int count = 0;
    for (;;) {
   
        if (type == &mp_type_object) {
   
            // 不是一个“真实”的类型,在这里结束搜索。
            return count;
        } else if (mp_obj_is_native_type(type)) {
   
            // 原生类型没有父类(至少从我们的角度来看是这样),所以结束。
            *last_native_base = type;
            return count + 1;
        #if MICROPY_MULTIPLE_INHERITANCE
        } else if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
   
            // 没有父类,所以在这里结束搜索。
            return count;
        } else {
   
            // 单个父类,使用迭代继续搜索。
            type = MP_OBJ_TYPE_GET_SLOT(type, parent);
        }
    #if MICROPY_MULTIPLE_INHERITANCE
        } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
   
            // 多个父类,递归搜索它们所有。
            const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
            const mp_obj_t *item = parent_tuple->items;
            const mp_obj_t *top = item + parent_tuple->len;
            for (; item < top; ++item) {
   
                assert(mp_obj_is_type(*item, &mp_type_type));
                const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
                count += instance_count_native_bases(bt, last_native_base);
            }
            return count;
        }
    #endif
    }
}

// 这个包装函数允许从原生类型派生的子类调用原生类型的
// __init__() 方法(对应于 type->make_new)。
static mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) {
   
    mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]);
    const mp_obj_type_t *native_base = NULL;
    instance_count_native_bases(self->base.type, &native_base);
    self->subobj[0] = MP_OBJ_TYPE_GET_SLOT(native_base, make_new)(native_base, n_args - 1, 0, args + 1);
    return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper);

#if !MICROPY_CPYTHON_COMPAT
static
#endif
mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_type_t **native_base) {
   
    size_t num_native_bases = instance_count_native_bases(class, native_base);
    assert(num_native_bases < 2);
    mp_obj_instance_t *o = mp_obj_malloc_var(mp_obj_instance_t, subobj, mp_obj_t, num_native_bases, class);
    mp_map_init(&o->members, 0);
    // 初始化原生基类槽(如果有的话),使用一个有效的对象。
    // 这个对象是什么并不重要,只要它能被唯一地识别为不是
    // 一个被初始化的原生类。
    if (num_native_bases != 0) {
   
        o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);
    }
    return o;
}

// TODO
// 这实现了深度优先左到右的 MRO,这与 Python3 MRO 不兼容
// http://python-history.blogspot.com/2010/06/method-resolution-order.html
// https://www.python.org/download/releases/2.3/mro/
// 将保持 lookup->dest[0] 的值(如果未找到属性,应该是 MP_OBJ_NULL)。如果在一个
// 原生类型基类中通过槽 ID 找到了特殊方法(如 lookup->slot_offset 指定的),将设置为 MP_OBJ_SENTINEL。
// 由于只能有一个原生基类,所以我们知道它适用于 instance->subobj[0]。在大多数情况下,我们也不需要知道
// 是哪个类型 - 因为 instance->subobj[0] 是那种类型的对象。
// 唯一的例外是当对象尚未构造时,我们需要知道基原生类型,以便从该类型构造其 instance->subobj[0]。
// 但是这种情况通过 instance_count_native_bases() 处理,它返回它看到的原生基类。
// 这个函数还处理了从 instance->subobj[0] 调用原生构造函数的情况,这在 CPython 中是不允许的。
struct class_lookup_data {
   
    mp_obj_instance_t *obj;
    qstr attr;
    size_t slot_offset;
    mp_obj_t *dest;
    bool is_type;
};

// 用于调试的打印
static void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_type_t *type) {
   
    assert(lookup->dest[0] == MP_OBJ_NULL);
    assert(lookup->dest[1] == MP_OBJ_NULL);
    for (;;) {
   
        DEBUG_printf("mp_obj_class_lookup: 在 %s 中查找 %s\n", qstr_str(lookup->attr), qstr_str(type->name));
        // 优化原生类型的特殊方法查找
        if (lookup->slot_offset != 0 && mp_obj_is_native_type(type)) {
   
            // 检查指定的槽索引是否有非零值,
            // 对于 getiter,槽不会设置,因为 MP_TYPE_FLAG_ITER_IS_STREAM。
            if (MP_OBJ_TYPE_HAS_SLOT_BY_OFFSET(type, lookup->slot_offset) || (lookup->slot_offset == MP_OBJ_TYPE_OFFSETOF_SLOT(iter) && type->flags & MP_TYPE_FLAG_ITER_IS_STREAM)) {
   
                DEBUG_printf("mp_obj_class_lookup: 匹配特殊方法槽(off=%d)为 %s\n",
                    lookup->slot_offset, qstr_str(lookup->attr));
                lookup->dest[0] = MP_OBJ_SENTINEL;
                return;
            }
        }

        if (MP_OBJ_TYPE_HAS_SLOT(type, locals_dict)) {
   
            // 在 locals_dict(方法/属性集)中搜索
            assert(mp_obj_is_dict_or_ordereddict(MP_OBJ_FROM_PTR(MP_OBJ_TYPE_GET_SLOT(type, locals_dict)))); // MicroPython 限制,目前是这样
            mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(type, locals_dict)->map;
            mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(lookup->attr), MP_MAP_LOOKUP);
            if (elem != NULL) {
   
                if (lookup->is_type) {
   
                    // 如果我们查找一个类方法,我们需要返回原始类型,而不是我们找到类方法的(基)类型。
                    const mp_obj_type_t *org_type = (const mp_obj_type_t *)lookup->obj;
                    mp_convert_member_lookup(MP_OBJ_NULL, org_type, elem->value, lookup->dest);
                } else {
   
                    mp_obj_instance_t *obj = lookup->obj;
                    mp_obj_t obj_obj;
                    if (obj != NULL && mp_obj_is_native_type(type) && type != &mp_type_object /* object 不是一个真实的类型 */) {
   
                        // 如果我们处理的是原生基类,那么它适用于原生子对象
                        obj_obj = obj->subobj[0];
                    } else {
   
                        obj_obj = MP_OBJ_FROM_PTR(obj);
                    }
                    mp_obj_instance_t *self = lookup->obj;
                    mp_obj_t self_in = MP_OBJ_FROM_PTR(self);
                    mp_convert_member_lookup(obj_obj, type, elem->value, lookup->dest);
                }
                #if DEBUG_PRINT
                DEBUG_printf("mp_obj_class_lookup: 返回: ");
                mp_obj_print_helper(MICROPY_DEBUG_PRINTER, lookup->dest[0], PRINT_REPR);
                if (lookup->dest[1] != MP_OBJ_NULL) {
   
                    // 尽量不要对 lookup->dest[1] 进行 repr(),因为我们可能会递归调用
                    DEBUG_printf(" <%s @%p>", mp_obj_get_type_str(lookup->dest[1]), MP_OBJ_TO_PTR(lookup->dest[1]));
                }
                DEBUG_printf("\n");
                #endif
                return;
            }
        }

        // 之前的代码块处理了 .locals_dict 中定义的属性,
        // 但是一些原生类型的属性可能使用 .load_attr 方法处理,
        // 所以确保我们也尝试查找这些属性。
        if (lookup->obj != NULL && !lookup->is_type && mp_obj_is_native_type(type) && type != &mp_type_object /* object 不是一个真实的类型 */) {
   
            mp_load_method_maybe(lookup->obj->subobj[0], lookup->attr, lookup->dest);
            if(lookup->dest[0] != MP_OBJ_NULL) {
   
                return;
            }
        }

        // 属性未找到,继续搜索基类

        if (!MP_OBJ_TYPE_HAS_SLOT(type, parent)) {
   
            DEBUG_printf("mp_obj_class_lookup: 没有更多的父类\n");
            return;
        #if MICROPY_MULTIPLE_INHERITANCE
        } else if (((mp_obj_base_t *)MP_OBJ_TYPE_GET_SLOT(type, parent))->type == &mp_type_tuple) {
   
            const mp_obj_tuple_t *parent_tuple = MP_OBJ_TYPE_GET_SLOT(type, parent);
            const mp_obj_t *item = parent_tuple->items;
            const mp_obj_t *top = item + parent_tuple->len - 1;
            for (; item < top; ++item) {
   
                assert(mp_obj_is_type(*item, &mp_type_type));
                mp_obj_type_t *bt = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
                if (bt == &mp_type_object) {
   
                    // 不是一个“真实”的类型
                    continue;
                }
                mp_obj_class_lookup(lookup, bt);
                if (lookup->dest[0] != MP_OBJ_NULL) {
   
                    return;
                }
            }

            // 搜索最后一个基类(简单的尾递归消除)
            assert(mp_obj_is_type(*item, &mp_type_type));
            type = (mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
        #endif
        } else {
   
            type = MP_OBJ_TYPE_GET_SLOT(type, parent);
        }
        if (type == &mp_type_object) {
   
            // 不是一个“真实”的类型
            return;
    }
}

// 实例打印
static void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
   
    mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
    qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;
    mp_obj_t member[2] = {
   MP_OBJ_NULL};
    struct class_lookup_data lookup = {
   
        .obj = self,
        .attr = meth,
        .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(print),
        .dest = member,
        .is_type = false,
    };
    mp_obj_class_lookup(&lookup, self->base.type);
    if (member[0] == MP_OBJ_NULL && kind == PRINT_STR) {
   
        // 如果没有 __str__,回退到 __repr__
        lookup.attr = MP_QSTR___repr__;
        lookup.slot_offset = 0;
        mp_obj_class_lookup(&lookup, self->base.type);
    }

    if (member[0] == MP_OBJ_SENTINEL) {
   
        // 特殊处理 Exception 子类
        if (mp_obj_is_native_exception_instance(self->subobj[0])) {
   
            if (kind != PRINT_STR) {
   
                mp_print_str(print, qstr_str(self->base.type->name));
            }
            mp_obj_print_helper(print, self->subobj[0], kind | PRINT_EXC_SUBCLASS);
        } else {
   
            mp_obj_print_helper(print, self->subobj[0], kind);
        }
        return;
    }

    if (member[0] != MP_OBJ_NULL) {
   
        mp_obj_t r = mp_call_function_1(member[0], self_in);
        mp_obj_print_helper(print, r, PRINT_STR);
        return;
    }

    // TODO: CPython 打印完全合格的类型名称
    mp_printf(print, "<%s object at %p>", mp_obj_get_type_str(self_in), self);
}

// 实例创建新的实例
static mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) {
   
    assert(mp_obj_is_instance_type(self));

    // 查找 __new__ 函数
    mp_obj_t init_fn[2] = {
   MP_OBJ_NULL};
    struct class_lookup_data lookup = {
   
        .obj = NULL,
        .attr = MP_QSTR___new__,
        .slot_offset = MP_OBJ_TYPE_OFFSETOF_SLOT(make_new),
        .dest = init_fn,
        .is_type = false,
    };
    mp_obj_class_lookup(&lookup, self);

    const mp_obj_type_t *native_base = NULL;
    mp_obj_instance_t *o;
    if (init_fn[0] == MP_OBJ_NULL || init_fn[0] == MP_OBJ_SENTINEL) {
   
        // 要么没有定义 __new__() 方法,要么有一个原生构造函数。
        // 在这两种情况下,创建一个空白实例。
        o = mp_obj_new_instance(self, &native_base);

        // 由于 type->make_new() 实现了 __new__() 和 __init__(),
        // 其中后者可能被 Python 子类覆盖,
        // 我们推迟调用原生构造函数(见本函数末尾),
        // 以便给 Python __init__() 方法一个机会来调用
        // 所述原生构造函数。

    } else {
   
        // 调用 Python 类的 __new__ 函数,用所有参数创建一个实例
        mp_obj_t new_ret;
        if (n_args == 0 && n_kw == 0) {
   
            mp_obj_t args2[1] = {
   MP_OBJ_FROM_PTR(self)};
            new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2);
        } else {
   
            mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw);
            args2[0] = MP_OBJ_FROM_PTR(self);
            memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
            new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
            m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);
        }

        // 根据 Python 3.4 参考数据模型 - object.__new__
        // "如果 __new__() 返回的不是 cls 的实例,则不会调用新实例的 __init__() 方法。"
        if (mp_obj_get_type(new_ret) != self) {
   
            return new_ret;
        }

        // __new__() 返回的实例成为新对象
        o = MP_OBJ_TO_PTR(new_ret);
    }

    // 现在调用 Python 类的 __init__ 函数,用所有参数
    // 这个方法有机会调用 super().__init__() 来构造可能的原生基类。
    init_fn[0] = init_fn
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

openwin_top

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

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

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

打赏作者

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

抵扣说明:

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

余额充值