MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.
microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
python编程示例系列 python编程示例系列二
python的Web神器Streamlit
这段代码是MicroPython中StringIO和BytesIO对象的实现,它们提供了在内存中读写字符串或字节序列的功能。代码中包含了对象的创建、读写、I/O控制操作以及本地方法字典的定义。这些对象可以像文件一样使用,但它们操作的是内存中的字符串或字节数据,而不是磁盘文件。
#include <stdio.h>
#include <string.h>
// 引入MicroPython对象和字符串I/O相关的头文件
#include "py/objstr.h"
#include "py/objstringio.h"
#include "py/runtime.h"
#include "py/stream.h"
#if MICROPY_PY_IO
// 如果定义了MICROPY_CPYTHON_COMPAT,则检查StringIO对象是否打开
#if MICROPY_CPYTHON_COMPAT
static void check_stringio_is_open(const mp_obj_stringio_t *o) {
if (o->vstr == NULL) {
mp_raise_ValueError(MP_ERROR_TEXT("I/O operation on closed file")); // 引发值错误,因为尝试对已关闭的文件执行I/O操作
}
}
#else
#define check_stringio_is_open(o)
#endif
// 打印StringIO对象的内容
static void stringio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self); // 打印对象类型和内存地址
}
// 从StringIO对象中读取数据
static mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
(void)errcode;
mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);
check_stringio_is_open(o); // 检查对象是否打开
if (o->vstr->len <= o->pos) {
// 如果读取到文件末尾或之后,则返回0
return 0;
}
mp_uint_t remaining = o->vstr->len - o->pos;
if (size > remaining) {
size = remaining; // 调整读取大小以不超过剩余内容
}
memcpy(buf, o->vstr->buf + o->pos, size); // 将数据从内部缓冲区复制到提供的缓冲区
o->pos += size; // 更新读取位置
return size; // 返回实际读取的字节数
}
// 在写操作时复制字符串I/O对象的内容,以便可以修改它
static void stringio_copy_on_write(mp_obj_stringio_t *o) {
const void *buf = o->vstr->buf;
o->vstr->buf = m_new(char, o->vstr->len); // 分配新的内存
o->vstr->fixed_buf = false; // 标记为非固定缓冲区
o->ref_obj = MP_OBJ_NULL; // 清除引用对象
memcpy(o->vstr->buf, buf, o->vstr->len); // 复制原始数据
}
// 向StringIO对象写入数据
static mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
(void)errcode;
mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);
check_stringio_is_open(o); // 检查对象是否打开
if (o->vstr->fixed_buf) {
stringio_copy_on_write(o); // 如果是固定缓冲区,则先复制内容
}
mp_uint_t new_pos = o->pos + size; // 计算新的写入位置
if (new_pos < size) {
// 如果写入大小导致位置溢出,则返回错误代码
*errcode = MP_EFBIG;
return MP_STREAM_ERROR;
}
mp_uint_t org_len = o->vstr->len;
if (new_pos > o->vstr->alloc) {
// 如果新位置超出了已分配的内存,则重新分配更多内存
vstr_add_len(o->vstr, new_pos - o->vstr->alloc);
}
// 如果之前已经移动到了文件末尾之后,将中间的空洞用零填充
if (o->pos > org_len) {
memset(o->vstr->buf + org_len, 0, o->pos - org_len);
}
memcpy(o->vstr->buf + o->pos, buf, size); // 将数据写入内部缓冲区
o->pos = new_pos; // 更新写入位置
if (new_pos > o->vstr->len) {
o->vstr->len = new_pos; // 更新字符串长度
}
return size; // 返回实际写入的字节数
}
// 执行I/O控制操作,如移动读写位置、刷新缓冲区、关闭文件等
static mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
(void)errcode;
mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);
switch (request) {
case MP_STREAM_SEEK: {
struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg;
mp_uint_t ref = 0;
switch (s->whence) {
case MP_SEEK_CUR:
ref = o->pos; // 从当前位置移动
break;
case MP_SEEK_END:
ref = o->vstr->len; // 从文件末尾移动
break;
}
mp_uint_t new_pos = ref + s->offset; // 计算新的位置
// 检查新位置是否有效
if (s->whence != MP_SEEK_SET && s->offset < 0) {
if (new_pos > ref) {
new_pos = 0; // 如果移动后的位置小于0,则重置为0
}
} else if (new_pos < ref) {
*errcode = MP_EINVAL; // 如果移动后的位置大于当前位置,则返回错误代码
return MP_STREAM_ERROR;