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/unicode.h"
#include "py/objstr.h"
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#if MICROPY_PY_BUILTINS_STR_OP_MODULO
// 如果启用了字符串的模运算符操作
static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_t *args, mp_obj_t dict);
#endif
// 创建一个新的字节迭代器对象
static mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
// 抛出异常,因为隐式类型转换不合法
static NORETURN void bad_implicit_conversion(mp_obj_t self_in);
// 根据vstr创建一个新的字符串类型对象
static mp_obj_t mp_obj_new_str_type_from_vstr(const mp_obj_type_t *type, vstr_t *vstr);
// 检查参数类型是否与对象类型相匹配
static void str_check_arg_type(const mp_obj_type_t *self_type, const mp_obj_t arg) {
// 字符串操作通常需要参数类型与调用它们的字符串类型相匹配
// 例如 str.find(str), byte.startswith(byte)
// 但字节数组可以用作字节字符串,反之亦然
#if MICROPY_PY_BUILTINS_BYTEARRAY
if (arg_type == &mp_type_bytearray) {
arg_type = &mp_type_bytes;
}
if (self_type == &mp_type_bytearray) {
self_type = &mp_type_bytes;
}
#endif
if (arg_type != self_type) {
bad_implicit_conversion(arg);
}
}
// 检查对象是否为字符串或字节类型
static void check_is_str_or_bytes(mp_obj_t self_in) {
mp_check_self(mp_obj_is_str_or_bytes(self_in));
}
// 打印带引号的字符串
void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes) {
// 此函数会转义字符,但打印速度会很慢(需要多次调用打印函数)
bool has_single_quote = false;
bool has_double_quote = false;
for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {
if (*s == '\'') {
has_single_quote = true;
} else if (*s == '"') {
has_double_quote = true;
}
}
int quote_char = '\'';
if (has_single_quote && !has_double_quote) {
quote_char = '"';
}
mp_printf(print, "%c", quote_char);
for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
if (*s == quote_char) {
mp_printf(print, "\\%c", quote_char);
} else if (*s == '\\') {
mp_print_str(print, "\\\\");
} else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) {
// 在字符串中,任何非ASCII控制字符都会被原样打印
mp_printf(print, "%c", *s);
} else if (*s == '\n') {
mp_print_str(print, "\\n");
} else if (*s == '\r') {
mp_print_str(print, "\\r");
} else if (*s == '\t') {
mp_print_str(print, "\\t");
} else {
mp_printf(print, "\\x%02x", *s);
}
}
mp_printf(print, "%c", quote_char);
}
#if MICROPY_PY_JSON
// 打印JSON格式的字符串
void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len) {
// 根据JSON规范打印字符串,详情见 http://www.ietf.org/rfc/rfc4627.txt
mp_print_str(print, "\"");
for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
if (*s == '"' || *s == '\\') {
mp_printf(print, "\\%c", *s);
} else if (*s >= 32) {
// 这将处理普通字符和UTF-8编码的字符
mp_printf(print, "%c", *s);
} else if (*s == '\n') {
mp_print_str(print, "\\n");
} else if (*s == '\r') {
mp_print_str(print, "\\r");
} else if (*s == '\t') {
mp_print_str(print, "\\t");
} else {
// 这将处理控制字符
mp_printf(print, "\\u%04x", *s);
}
}
mp_print_str(print, "\"");
}
#endif
// 打印字符串
static void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
GET_STR_DATA_LEN(self_in, str_data, str_len);
#if MICROPY_PY_JSON
if (kind == PRINT_JSON) {
mp_str_print_json(print, str_data, str_len);
return;
}
#endif
#if !MICROPY_PY_BUILTINS_STR_UNICODE
// 如果没有启用Unicode支持,则判断是否为字节类型
bool is_bytes = mp_obj_is_type(self_in, &mp_type_bytes);
#else
bool is_bytes = true;
#endif
if (kind == PRINT_RAW || (!MICROPY_PY_BUILTINS_STR_UNICODE && kind == PRINT_STR && !is_bytes)) {
print->print_strn(print->data, (const char *)str_data, str_len);
} else {
if (is_bytes) {
print->print_strn(print->data, "b", 1);
}
mp_str_print_quoted(print, str_data, str_len, is_bytes);
}
}
// 创建新的字符串对象
mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
#if MICROPY_CPYTHON_COMPAT
// 兼容CPython的关键字参数
if (n_kw != 0) {
mp_arg_error_unimpl_kw();
}
#endif
mp_arg_check_num(n_args, n_kw, 0, 3, false);
// 根据参数数量选择创建字符串的方式
switch (n_args) {
case 0:
return MP_OBJ_NEW_QSTR(MP_QSTR_);
case 1: {
// 从单个参数创建字符串
vstr_t vstr;
mp_print_t print;
vstr_init_print(&vstr, 16, &print);
mp_obj_print_helper(&print, args[0], PRINT_STR);
return mp_obj_new_str_type_from_vstr(type, &vstr);
}
default: // 2 或 3 个参数
// 验证第二个和第三个参数
if (mp_obj_is_type(args[0], &mp_type_bytes)) {
// 处理字节类型的参数
GET_STR_DATA_LEN(args[0], str_data, str_len);
GET_STR_HASH(args[0], str_hash);
if (str_hash == 0) {
str_hash = qstr_compute_hash(str_data, str_len);
}
#if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
// 检查UTF-8编码
if (!utf8_check(str_data, str_len)) {
mp_raise_msg(&mp_type_UnicodeError, NULL);
}
#endif
// 查找是否存在相同的qstr
qstr q = qstr_find_strn((const char *)str_data, str_len);
if (q != MP_QSTRnull) {
return MP_OBJ_NEW_QSTR(q);
}
mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len));
o->data = str_data;
o->hash = str_hash;
return MP_OBJ_FROM_PTR(o);
} else {
// 处理其他类型的参数
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
// 这将检查输入的UTF-8编码
return mp_obj_new_str(bufinfo.buf, bufinfo.len);
}
}
}
// 创建新的字节对象
static mp_obj_t bytes_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;
#if MICROPY_CPYTHON_COMPAT
// 兼容CPython的关键字参数
if (n_kw != 0) {
mp_arg_error_unimpl_kw();
}
#else
(void)n_kw;
#endif
if (n_args == 0) {
return mp_const_empty_bytes;
}
if (mp_obj_is_type(args[0], &mp_type_bytes)) {
// 如果参数已经是字节类型,则直接返回
return args[0];
}
if (mp_obj_is_str(args[0])) {
// 如果参数是字符串类型
if (n_args < 2 || n_args > 3) {
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
goto wrong_args;
#else
mp_raise_TypeError(MP_ERROR_TEXT("string argument without an encoding"));
#endif
}
GET_STR_DATA_LEN(args[0], str_data, str_len);
GET_STR_HASH(args[0], str_hash);
if (str_hash == 0) {
str_hash = qstr_compute_hash(str_data, str_len);
}
#if MICROPY_PY_BUILTINS_STR_UNICODE_CHECK
// 检查UTF-8编码
if (!utf8_check(str_data, str_len)) {
mp_raise_msg(&mp_type_UnicodeError, NULL);
}
#endif
// 查找是否存在相同的qstr
qstr q = qstr_find_strn((const char *)str_data, str_len);
if (q != MP_QSTRnull) {
return MP_OBJ_NEW_QSTR(q);
}
mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len));
o->data = str_data;
o->hash = str_hash;
return MP_OBJ_FROM_PTR(o);
}
if (n_args > 1) {
goto wrong_args;
}
if (mp_obj_is_small_int(args[0])) {
// 如果参数是小整数类型
mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]);
if (len < 0) {
mp_raise_ValueError(NULL);
}
vstr_t vstr;
vstr_init_len(&vstr, len);
memset(vstr.buf, 0, len);
return mp_obj_new_bytes_from_vstr(&vstr);
}
// 检查参数是否支持缓冲协议
mp_buffer_info_t bufinfo;
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {
return mp_obj_new_bytes(bufinfo.buf, bufinfo.len);
}
vstr_t vstr;
// 如果初始化长度已知,则尝试创建长度精确的数组
mp_obj_t len_in = mp_obj_len_maybe(args[0]);
if (len_in == MP_OBJ_NULL) {
vstr_init(&vstr, 16);
} else {
mp_int_t len = MP_OBJ_SMALL_INT_VALUE(len_in);
vstr_init(&vstr, len);
}
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(args[0], &iter_buf);
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
mp_int_t val = mp_obj_get_int(item);
#if MICROPY_FULL_CHECKS
// 检查值是否在字节范围内
if (val < 0 || val > 255) {
mp_raise_ValueError(MP_ERROR_TEXT("bytes value out of range"));
}
#endif
vstr_add_byte(&vstr, val);
}
return mp_obj_new_bytes_from_vstr(&vstr);
wrong_args:
// 参数数量不正确
mp_raise_TypeError(MP_ERROR_TEXT("wrong number of arguments"));
}
// 查找子字节串
// 与strstr类似,但是可以指定长度,并且允许\0字节
// 可以根据指定的方向(正向或反向)在haystack中查找needle
const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction) {
if (hlen >= nlen) {
size_t str_index, str_index_end;
if (direction > 0) {
str_index = 0;
str_index_end = hlen - nlen;
} else {
str_index = hlen - nlen;
str_index_end = 0;
}
for (;;) {
if (memcmp(&haystack[str_index], needle, nlen) == 0) {
// 找到匹配的子字节串
return haystack + str_index;
}
if (str_index == str_index_end) {
// 未找到
break;
}
str_index += direction;
}
}
return NULL;
}
// 字符串或字节类型的二元操作
mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// 检查是否为模运算符操作
if (op == MP_BINARY_OP_MODULO) {
#if MICROPY_PY_BUILTINS_STR_OP_MODULO
// 处理模运算符操作
mp_obj_t *args = &rhs_in;
size_t n_args = 1;
mp_obj_t dict = MP_OBJ_NULL;
if (mp_obj_is_type(rhs_in, &mp_type_tuple)) {
// 处理元组类型的参数
mp_obj_tuple_get(rhs_in, &n_args, &args);
} else if (mp_obj_is_type(rhs_in, &mp_type_dict)) {
// 处理字典类型的参数
dict = rhs_in;
}
return str_modulo_format(lhs_in, n_args, args, dict);
#else
return MP_OBJ_NULL;
#endif
}
// 从现在起我们需要lhs的类型和数据,所以提取它们
const mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in);
GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len);
// 检查是否为乘法操作
if (op == MP_BINARY_OP_MULTIPLY) {
mp_int_t n;
if (!mp_obj_get_int_maybe(rhs_in, &n)) {
return MP_OBJ_NULL; // 操作不支持
}
if (n <= 0) {
if (lhs_type == &mp_type_str) {
// 返回空字符串
return MP_OBJ_NEW_QSTR(MP_QSTR_);
} else {
// 返回空字节对象
return mp_const_empty_bytes;
}
}
vstr_t vstr;
vstr_init_len(&vstr, lhs_len * n);
mp_seq_multiply(lhs_data, sizeof(*lhs_data), lhs_len, n, vstr.buf);
return mp_obj_new_str_type_from_vstr(lhs_type, &vstr);
}
// 从现在起所有操作都允许:
// - 字符串与字符串
// - 字节与字节
// - 字节与字节数组
// - 字节与array.array
// 为了高效地执行这些操作,我们使用缓冲协议提取rhs的原始数据,
// 但仅当lhs是字节对象时。
const byte *rhs_data;
size_t rhs_len;
if (lhs_type == mp_obj_get_type(rhs_in)) {
// 如果左右操作数类型相同,直接获取数据
GET_STR_DATA_LEN(rhs_in, rhs_data_, rhs_len_);
rhs_data = rhs_data_;
rhs_len = rhs_len_;
} else if (lhs_type == &mp_type_bytes) {
// 如果lhs是字节类型,rhs必须支持缓冲协议
mp_buffer_info_t bufinfo;
if (!mp_get_buffer(rhs_in, &bufinfo, MP_BUFFER_READ)) {
return MP_OBJ_NULL; // 操作不支持
}
rhs_data = bufinfo.buf;
rhs_len = bufinfo.len;
} else {
// 如果lhs是字符串类型,rhs类型不兼容
// (除了相等操作,因为mp_obj_equal()会处理这种情况)
// 其他所有操作都不支持,可能会由其他类型处理,例如反向操作。
// CONTAINS操作必须抛出bad-implicit-conversion异常,因为
// 否则mp_binary_op()会回退到`list(lhs).__contains__(rhs)`。
if (op == MP_BINARY_OP_CONTAINS) {
bad_implicit_conversion(rhs_in);
}
// 所有其他操作都不支持,可以由其他类型处理。
return MP_OBJ_NULL;
}
// 根据操作符执行相应的操作
switch (op) {
case MP_BINARY_OP_ADD:
case MP_BINARY_OP_INPLACE_ADD: {
// 处理加法操作
if (lhs_len == 0 && mp_obj_get_type(rhs_in) == lhs_type) {
return rhs_in;
}
if (rhs_len == 0) {
return lhs_in;
}
vstr_t vstr;
vstr_init_len(&vstr, lhs_len + rhs_len);
memcpy(vstr.buf, lhs_data, lhs_len);
memcpy(vstr.buf + lhs_len, rhs_data,rhs_len);
return mp_obj_new_str_type_from_vstr(lhs_type, &vstr);
}
case MP_BINARY_OP_CONTAINS:
// 检查是否包含子字节串
return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL);
// case MP_BINARY_OP_NOT_EQUAL: // 这里永远不会传入这个操作
case MP_BINARY_OP_EQUAL: // 这将只为字节传入,字符串在mp_obj_equal()中处理
case MP_BINARY_OP_LESS:
case MP_BINARY_OP_LESS_EQUAL:
case MP_BINARY_OP_MORE:
case MP_BINARY_OP_MORE_EQUAL:
// 比较两个序列
return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_data, lhs_len, rhs_data, rhs_len));
default:
// 操作不支持
return MP_OBJ_NULL;
}
}
#if !MICROPY_PY_BUILTINS_STR_UNICODE
// objstrunicode定义了自己的版本
const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
mp_obj_t index, bool is_slice) {
// 根据索引获取指向字符串中特定位置的指针
size_t index_val = mp_get_index(type, self_len, index, is_slice);
return self_data + index_val;
}
#endif
// 字节或字符串的索引操作
static mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
const mp_obj_type_t *type = mp_obj_get_type(self_in);
GET_STR_DATA_LEN(self_in, self_data, self_len);
if (value == MP_OBJ_SENTINEL) {
// 加载操作
#if MICROPY_PY_BUILTINS_SLICE
if (mp_obj_is_type(index, &mp_type_slice)) {
// 处理切片操作
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self_len, index, &slice)) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("only slices with step=1 (aka None) are supported"));
}
return mp_obj_new_str_of_type(type, self_data + slice.start, slice.stop - slice.start);
}
#endif
size_t index_val = mp_get_index(type, self_len, index, false);
// 如果启用了Unicode支持,则类型总是字节,所以采取捷径
if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) {
return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);
} else {
return mp_obj_new_str_via_qstr((char *)&self_data[index_val], 1);
}
} else {
// 赋值操作不支持
return MP_OBJ_NULL;
}
}
// 字符串连接操作
static mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) {
check_is_str_or_bytes(self_in);
const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
const mp_obj_type_t *ret_type = self_type;
// 获取分隔符字符串
GET_STR_DATA_LEN(self_in, sep_str, sep_len);
// 处理参数
size_t seq_len;
mp_obj_t *seq_items;
if (!mp_obj_is_type(arg, &mp_type_list) && !mp_obj_is_type(arg, &mp_type_tuple)) {
// 参数不是列表也不是元组,尝试将其转换为列表
arg = mp_obj_list_make_new(&mp_type_list, 1, 0, &arg);
}
mp_obj_get_array(arg, &seq_len, &seq_items);
// 计算所需长度
size_t required_len = 0;
#if MICROPY_PY_BUILTINS_BYTEARRAY
if (self_type == &mp_type_bytearray) {
self_type = &mp_type_bytes;
}
#endif
for (size_t i = 0; i < seq_len; i++) {
const mp_obj_type_t *seq_type = mp_obj_get_type(seq_items[i]);
#if MICROPY_PY_BUILTINS_BYTEARRAY
if (seq_type == &mp_type_bytearray) {
seq_type = &mp_type_bytes;
}
#endif
if (seq_type != self_type) {
// 参数类型不匹配
mp_raise_TypeError(
MP_ERROR_TEXT("join expects a list of str/bytes objects consistent with self object"));
}
if (i > 0) {
required_len += sep_len;
}
GET_STR_LEN(seq_items[i], l);
required_len += l;
}
// 创建连接后的字符串
vstr_t vstr;
vstr_init_len(&vstr, required_len);
byte *data = (byte *)vstr.buf;
for (size_t i = 0; i < seq_len; i++) {
if (i > 0) {
memcpy(data, sep_str, sep_len);
data += sep_len;
}
GET_STR_DATA_LEN(seq_items[i], s, l);
memcpy(data, s, l);
data += l;
}
// 返回连接后的字符串
return mp_obj_new_str_type_from_vstr(ret_type, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join);
// 字符串分割操作
mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) {
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
mp_int_t splits = -1;
mp_obj_t sep = mp_const_none;
if (n_args > 1) {
sep = args[1];
if (n_args > 2) {
splits = mp_obj_get_int(args[2]);
}
}
mp_obj_t res = mp_obj_new_list(0, NULL);
GET_STR_DATA_LEN(args[0], s, len);
const byte *top = s + len;
if (sep == mp_const_none) {
// 未给出分隔符,根据空白字符分割
// 初始空白字符不计入分割,所以预先处理
while (s < top && unichar_isspace(*s)) {