# Pikapython

> PikaPython 应用与 C 模块二次开发指南；开发 parser、VM、runtime 或内核时不使用本 skill。

- Skill: `pikastech/pikapython` (Agent Skill)
- Install (CLI): `npx skillmds@latest add pikastech/pikapython`
- Raw SKILL.md: https://api.skillmd.com/api/skills/pikastech/pikapython/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: pikastech (https://skillmd.com/u/pikastech)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/pikastech/pikapython

---


你是一个“Python -> PikaPython C 模块”转换与执行代理。

## 适用范围

- 本 skill 只服务 PikaPython 用户二次开发：
  - 编写应用脚本和兼容 PikaPython 子集的 Python 代码；
  - 开发 `.pyi` 接口与 C 扩展模块；
  - 为用户模块编写功能测试和 Python/C 实现性能对比；
  - 调试用户模块的类型、对象生命周期和 API 使用问题。
- 本 skill 不负责 PikaPython 自身开发：
  - parser、VM、runtime 和核心库修改；
  - Linux GTest、内核 benchmark、热点分析和 RAM/Flash A/B；
  - 内核错误合同、可选依赖隔离和版本发布验证。
- PikaPython 自身开发统一在私有 `pikasTech/pika_workspace` 执行，并以
  `SKILL.md` 与 `docs/reference/kernel-development.md` 为权威入口。

## 1 角色与总体目标

给定一段 Python 功能代码（函数 / 类），需自动：生成 PikaPython C 模块 -> 生成测试脚本 -> 构建与运行 -> 提取结果 / 处理错误。

> 重要提醒：PikaPython环境仅支持Python语法子集，标准库极度精简，类型系统严格，所有实现需优先兼容性与健壮性，详见后续章节。

## 2 执行阶段

### 2.1 模块生成

在 `file_create/<session_path>/<module_name>` 下生成：

1. 接口：`<module_name>.pyi`。在 `.pyi` 文件中，方法体可以使用 `pass` 或 `...`，两者等效。
2. 实现：一个或多个 `<module_name>_<ClassName>.c`
3. C 函数命名：`<module_name>_<ClassName>_<methodName>`
4. 字符串返回使用：`obj_cacheStr(self, buf)`

### 2.2 测试脚本生成（功能优先，性能后置）

重要提示：在编写 py_... 基线函数前，请务必回顾 6.1 和 6.1.2 节的限制与原则。一个不符合 PikaPython 语法子集的基线核心思想：当简洁性与兼容性冲突时，无条件选择兼容性。一个能在 PikaPython 中正确运行的"笨拙"基线函数，远胜于一个在标准 Python 中高效但无法运行的"优雅"函数。 


### 2.3 构建与运行

执行命令：`python run_pika.py --module <module_name> --module-dir file_create/<session_path> file_create/<session_path>/test_example.py`

常见误区: 误以为 `run_pika.py` 在 `pikapython-linux` 目录下。实际上它在项目根目录，完全不需要用任何的 `cd` 命令切换目录。
错误示例：`cd ./pikapython-linux && python run_pika.py --module <module_name> --module-dir ../file_create/<session_path> ../file_create/<session_path>/test_example.py` 原因: `run_pika.py` 不在 `pikapython-linux` 目录下所以会出错。

### 2.4 结果提取

从最新 `logs/run/<timestamp>/run.log` 中提取：`[EXAMPLE]`、`[PERF]`、`[EXAMPLE][SELFTEST]` 行。

### 2.5 错误处理

构建失败：读取 `compile.log` 末 40 行，输出 `[BUILD_FAIL] <摘要>`。
运行失败：读取 `run.log` 末 40 行，输出 `[RUN_FAIL] <摘要>`。

## 3 命名与实现规范

### 3.1 文件与路径

允许写入：`file_create/<session_path>/<module_name>/*.pyi`、`file_create/<session_path>/<module_name>/*.c`、`file_create/<session_path>/test_example.py`。无需也禁止对目录执行 `read_file`。

### 3.2 C 文件/函数命名

文件：`<module_name>_<ClassName>.c`
函数：`<module_name>_<ClassName>_<methodName>`
示例：

```
模块: math_add
类:   MathAdd
方法: add
文件: math_add_MathAdd.c
函数: math_add_MathAdd_add
```

示例实现：

```c
#include "math_add_MathAdd.h"
int math_add_MathAdd_add(PikaObj* self, int a, int b){
    return a + b;
}
```

### 3.2.1 C 文件头文件规范

* **核心包含**: C 实现文件**必须**包含 `#include "<module_name>_<ClassName>.h"` 以获得 pyi 生成的 binding 的头文件定义，PikaPython 的核心类型与 API 定义。

* **标准库包含**: 如果需要使用标准 C 库函数（如 `strcmp`, `snprintf`），则**必须**包含相应的头文件（如 `#include <string.h>`, `#include <stdio.h>`)。**绝对不应该**包含 PikaPython 项目内部的其他非 `<module_name>_<ClassName>.h` 的头文件。

### 3.2.2 函数封装规范

  *   **强制类封装**: 所有 Python 功能，即使用户仅提供独立函数，在生成 C 模块时也**必须**被封装在一个类中。不允许生成直接映射到 C 的顶层函数。

### 3.3 返回值与字符串

* **浮点返回**: 优先使用 `pika_float` 以避免被解释器截断为 `0.0`。

* **字符串返回**: 当返回函数内的局部变量字符串时，必须使用 `obj_cacheStr()` 进行缓存，以防悬垂引用。

  ```c
  char buf[32];
  snprintf(buf, sizeof(buf), "%d", value);
  return obj_cacheStr(self, buf);
  ```

* **函数签名陷阱**: C 函数的返回类型必须与接口头文件严格匹配。返回 `Arg*` 而接口期望 `PikaObj*` 会导致 "conflicting types" 编译错误。返回对象时使用 `PikaObj*`（返回 `NULL` 表示 None），返回混合类型时使用 `Arg*`（用 `arg_newObj()` 包装对象）。

* **Arg* 返回值处理 (重要先验知识)**: 

  * **核心陷阱**: 不能直接引用或复制现有的 `Arg*` 对象返回。`arg_incRef()` 和 `arg_newRef()` 等API可能不存在或参数类型不匹配。

  * **正确模式**: 根据数据类型使用对应的构造函数创建新的 `Arg*` 对象：

    ```c
    // 错误：尝试引用现有对象
    return arg_incRef(existing_arg); // 函数不存在
    return arg_newRef(existing_arg); // 参数类型不匹配
    
    // 正确：创建新的类型特定对象
    if (arg_getType(result_arg) == ARG_TYPE_INT) {
        return arg_newInt(arg_getInt(result_arg));
    } else if (arg_getType(result_arg) == ARG_TYPE_FLOAT) {
        return arg_newFloat(arg_getFloat(result_arg));
    } else if (arg_getType(result_arg) == ARG_TYPE_STRING) {
        return arg_newStr(arg_getStr(result_arg));
    }
    ```

  * **常见误区**: 认为可以像标准C一样直接返回指针或引用对象。在PikaPython中，必须通过API构造函数创建运行时可识别的对象。

  * **重要提醒**: 处理混合数据类型时，务必先通过 `arg_getType()` 检查类型，再使用对应的 `arg_get*()` 函数获取值，否则可能导致类型不匹配错误。

* **bytes 返回**: `bytes` 作为返回值时，C 函数应返回 `Arg*` 类型。必须使用 `arg_newBytes(bytes_ptr, len)` 来创建返回值。

  ```c
  // 示例: 返回一个 bytes 对象
  uint8_t data[] = {0x01, 0x02, 0x03};
  return arg_newBytes(data, sizeof(data));
  ```

### 3.4 `None` 值与复杂返回值处理（重要）

#### 3.4.1 `None` 值的正确处理 API

处理 `None` 是常见的失败点。必须使用以下标准 API：

* **返回 `None`**: 使用 `arg_newNone()`。此函数返回一个 `Arg*` 类型的 `None` 值。

  ```c
  // 正确示例: 当列表为空时返回 None
  if (pikaList_getSize(nums) == 0) {
      return arg_newNone();
  }
  ```

* **检查 `None`**: 使用 `arg_getType(arg) == ARG_TYPE_NONE`。

  ```c
  // 正确示例: 检查返回值是否为 None
  Arg* result = some_function(self, nums);
  if (arg_getType(result) == ARG_TYPE_NONE) {
      // 处理 None 的情况
  }
  ```

* **常见误区**:

  *   **禁止使用 `arg_setNull(NULL)`**: 这是一个过时且类型不安全的宏，会引发编译警告或错误。
  *   **禁止使用 `arg_isNull(...)`**: 这个函数不存在，会导致链接错误。

#### 3.4.2 处理“对象或 None”的返回值

当一个 C 函数可能返回一个 PikaPython 对象（如 `list`, `tuple`, `dict`）或者 `None` 时，该函数的返回类型**必须**声明为 `Arg*`。

* **函数签名**:

  ```c
  // 错误: PikaObj* 无法直接承载 None
  PikaObj* my_function(PikaObj* self, PikaObj* nums);
  
  // 正确: Arg* 可以同时代表对象和 None
  Arg* my_function(PikaObj* self, PikaObj* nums);
  ```

* **返回对象 (重要修正)**: 当返回一个 PikaPython 对象（如 `PikaTuple*`, `PikaList*`）时，**必须**使用 `arg_newObj()` 将其包装成 `Arg*`。一律使用 `arg_newObj` 以减少显式类型参数与误用风险。

  *   **推荐用法**: `arg_newObj((PikaObj*)some_obj)`
  *   **常见误区**: 不要使用 `arg_setPtr()` 试图原地修改；那通常需要已有 `Arg` 实例，且更容易产生生命周期或类型不匹配问题。

  ```c
  // 正确示例: 返回一个元组对象
  PikaTuple* tuple = New_PikaTuple();
  // ... 填充 tuple ...
  return arg_newObj((PikaObj*)tuple);
  ```

* **安全地使用返回值**: 从 `Arg*` 类型的返回值中提取对象指针前，**必须**先检查它是否为 `None`，否则可能导致段错误。

  ```c
  Arg* result_arg = my_function(self, nums);
  
  // 1. 必须先检查 None
  if (arg_getType(result_arg) == ARG_TYPE_NONE) {
      // ... 处理 None ...
      return;
  }
  
  // 2. 确认不是 None 后，再安全地获取对象指针
  PikaObj* result_obj = arg_getPtr(result_arg);
  // ... 在此使用 result_obj ...
  ```

在 `test_example.py` 中，始终使用 `is None` 来断言 `None` 值。

```python
val_mod = stats.min_max([])
assert val_mod is None, "min_max of empty list should be None"
```

### 3.5 列表 (List)、元组 (Tuple)、字典 (Dict) 操作指南

#### 3.5.1 **核心陷阱：Python `int` 与 C `float` 的类型不匹配**

**警告：这是最常见的失败原因！** 当一个包含整数的 Python 列表（如 `[1, 2, 3]`）被传递到 C 模块时，其元素的类型是 `ARG_TYPE_INT`。如果你直接使用 `arg_getFloat()` 或 `pikaList_getFloat()` 去读取这些值，你会得到 `0.0` 而不是期望的整数值。

**正确的数据提取模式：**
必须先获取通用 `Arg*`，然后检查其类型，最后使用对应的 `get` 函数。

```c
// 正确的、健壮的列表遍历方式
int len = pikaList_getSize((PikaList*)nums); // 注意：参数通常是 PikaObj*，需要强制转换
for (int i = 0; i < len; i++) {
    Arg* arg = pikaList_get((PikaList*)nums, i);
    pika_float val = 0.0;

    // 检查类型并分别处理
    if (arg_getType(arg) == ARG_TYPE_INT) {
        val = (pika_float)arg_getInt(arg);
    } else if (arg_getType(arg) == ARG_TYPE_FLOAT) {
        val = arg_getFloat(arg);
    }
    
    // ... 在此处理 val ...
}
```

#### 3.5.2 PikaPython 核心对象创建与操作

* **创建空对象**:

  *   `PikaList* my_list = New_PikaList();`
  *   `PikaTuple* my_tuple = New_PikaTuple();`
  *   `PikaDict* my_dict = New_PikaDict();`
  *   **错误用法**: 不要使用 `newNormalObj(New_List)`，这是过时且错误的。

* **列表 (List) 操作**:

  * 添加元素: `pikaList_append(my_list, arg_newFloat(3.14));`

  * 获取长度: `int len = pikaList_getSize(my_list);`

  * 获取元素: `Arg* val_arg = pikaList_get(my_list, i);` (参见 3.5.1 的类型处理)

  * **列表遍历 (重要先验知识)**:

    * **推荐模式：使用 `pikaList_forEach` 回调**: 这是遍历列表最健壮、最高效的方法。

    * **核心陷阱**: `pikaList_forEach` 的回调函数签名是固定的，必须包含 `itemIndex` 参数。错误的签名会导致编译警告 (`-Wincompatible-pointer-types`) 和潜在的运行时错误。

    * **正确签名**: `int32_t callback(PikaObj* self, int itemIndex, Arg* itemEach, void* context)`

    * **示例**:

      ```c
      // 1. 定义一个上下文结构体来持有状态
      typedef struct {
          PikaList* integers;
          PikaList* strings;
      } MyContext;
      
      // 2. 实现回调函数 (注意 itemIndex 参数)
      int32_t process_item_callback(PikaObj* self, int itemIndex, Arg* item_arg, void* context) {
          MyContext* ctx = (MyContext*)context;
          if (arg_getType(item_arg) == ARG_TYPE_INT) {
              pikaList_append(ctx->integers, item_arg);
          } else if (arg_getType(item_arg) == ARG_TYPE_STRING) {
              pikaList_append(ctx->strings, item_arg);
          }
          return 0; // 返回 0 以继续遍历
      }
      
      // 3. 在主函数中调用 forEach
      MyContext ctx = { .integers = New_PikaList(), .strings = New_PikaList() };
      pikaList_forEach((PikaList*)items, process_item_callback, &ctx);
      // 遍历结束后, ctx.integers 和 ctx.strings 将包含所需结果
      ```

* **元组 (Tuple) 操作**:

  * 元组在 C 层面通常被当作**不可变列表**处理。

  * 创建并填充元组:

    ```c
    PikaTuple* tuple = New_PikaTuple();
    pikaList_append((PikaList*)tuple, arg_newFloat(val1));
    pikaList_append((PikaList*)tuple, arg_newFloat(val2));
    return (PikaObj*)tuple; // 返回时转换为 PikaObj*
    ```

  * 读取元组:

    ```c
    // 假设 min_max_tuple 是一个 PikaObj*
    pika_float mn = pikaList_getFloat((PikaList*)min_max_tuple, 0);
    ```

* **字典 (Dict) 操作**:

  * 设置键值对:

    ```c
    pikaDict_setFloat(my_dict, "mean", 12.3);
    pikaDict_setInt(my_dict, "count", 5);
    pikaDict_setStr(my_dict, "status", "ok");
    ```

  * **核心陷阱：在字典中存储对象（如列表、其他字典）**

    * **问题描述**: 当你希望一个字典的值是另一个 PikaPython 对象（例如，一个 `PikaList*`）时，一个致命的错误是使用 `pikaDict_setPtr()`。这个函数只会存储该对象的原始内存地址（指针），而不是运行时可识别的对象引用。

    * **错误后果**: 在 Python 测试脚本中，当你访问这个字典键时，你得到的是一个无法使用的整数（内存地址），而不是一个可操作的列表或字典对象。对其调用 `len()` 或进行索引将导致 `TypeError` 或 `len: arg type not support` 错误。

    * **常见误区 (错误示例)**:

      ```c
      PikaList* evens_list = New_PikaList();
      // ... 填充列表 ...
      // 错误！这只存储了 evens_list 的地址，Python 端无法使用
      pikaDict_setPtr(result_dict, "even", (PikaObj*)evens_list);
      ```

    * **正确模式：使用 `arg_newObj()` 和 `pikaDict_set()`**:

      1.  创建你的对象（例如 `PikaList*`）。
      2.  使用 `arg_newObj()` 将该对象包装成一个运行时可识别的 `Arg*`。
      3.  使用 `pikaDict_set()` 将这个 `Arg*` 存入字典。

      ```c
      // 正确示例
      PikaList* evens_list = New_PikaList();
      // ... 填充列表 ...
      // 1. 将 PikaList* 包装成 Arg*
      Arg* arg_list = arg_newObj((PikaObj*)evens_list);
      // 2. 将 Arg* 存入字典
      pikaDict_set(result_dict, "even", arg_list);
      ```

  * **先验知识：字典与复杂对象**: PikaPython 的字典在处理嵌套的复杂对象（尤其是返回 `None` 的情况）时可能存在不稳定性，容易引发 `arg_isCallable` 等运行时断言失败。

  * **避障策略**: 如果一个函数返回字典，且该字典的值包含其他函数调用的结果（特别是可能返回 `None` 或其他对象的函数），应优先简化或避免这种结构。如果遇到难以调试的运行时崩溃，可尝试将返回字典的复杂函数从测试中暂时移除，以优先确保其他核心功能的正确性。

  * **字典 (Dict) 遍历 (重要先验知识)**

    * **核心陷阱**: PikaPython 的 C API 中 **不存在** `pikaDict_keys()` 函数。尝试调用它会导致 `undefined reference` 编译错误。

    * **重要提醒**: 使用 `pikaDict_get()` 返回值前，必须检查是否为 `NULL`，否则会导致断言失败 `"self != 0"`。

    * **正确模式 1：通过索引遍历 (不推荐但可用)**

      *   **API**: `pikaDict_getSize()` 和 `pikaDict_getArgByindex()`。
      *   **描述**: 此方法通过索引 `i` 从 `0` 到 `size-1` 遍历字典。`pikaDict_getArgByindex()` 返回的是**键**的 `Arg*`。你需要用这个键再次调用 `pikaDict_get()` 来获取值。
      *   **缺点**: 效率较低，且容易出错（例如，忘记检查 `NULL` 返回值）。

      ```c
      int dict_size = pikaDict_getSize(counts);
      for (int i = 0; i < dict_size; i++) {
          Arg* key_arg = pikaDict_getArgByindex(counts, i);
          if (key_arg == NULL) continue;
          
          char* key = arg_getStr(key_arg);
          Arg* count_arg = pikaDict_get(counts, key);
          // ... process count_arg ...
      }
      ```

    * **正确模式 2：使用 `forEach` 回调 (强烈推荐)**

      * **API**: `pikaDict_forEach()`。

      * **描述**: 这是遍历字典最健壮、最高效的方法。它接受一个回调函数，该函数会对字典中的每一个键值对被调用。你可以通过一个上下文结构体 (`context`) 来传递和修改状态。

      * **示例**:

        ```c
        // 1. 定义一个上下文结构体来持有状态
        typedef struct {
            int max_count;
            char max_key[128];
        } MaxCountContext;
        
        // 2. 实现回调函数
        int32_t find_max_count_callback(PikaObj* self, Arg* keyEach, Arg* valEach, void* context) {
            MaxCountContext* ctx = (MaxCountContext*)context;
            int count = arg_getInt(valEach);
            if (count > ctx->max_count) {
                ctx->max_count = count;
                // 关键：从 keyEach (这是一个 Arg*) 中获取字符串
                char* key_str = arg_getStr(keyEach);
                // 安全地更新上下文中的 max_key
                strncpy(ctx->max_key, key_str, sizeof(ctx->max_key) - 1);
                ctx->max_key[sizeof(ctx->max_key) - 1] = '\\0';
            }
            return 0; // 返回 0 以继续遍历
        }
        
        // 3. 在主函数中调用 forEach
        MaxCountContext ctx = {0, ""}; // 初始化上下文
        pikaDict_forEach((PikaObj*)counts, find_max_count_callback, &ctx);
        // 遍历结束后, ctx.max_key 和 ctx.max_count 将包含所需结果
        ```

  * **先验知识：使用格式化字符串作为复合键 (最佳实践)**: PikaPython 的字典键必须是字符串。当需要根据不同类型的列表元素（如整数、浮点数、字符串）进行计数或分组时，一个非常有效且健壮的策略是在 C 代码中通过 `snprintf` 将这些元素格式化为带类型前缀的唯一字符串键（例如，`"i_123"` 代表整数 `123`，`"s_apple"` 代表字符串 `"apple"`）。这可以完美解决 PikaPython 字典无法直接使用非字符串类型作为键的限制，并能可靠地处理混合数据类型。在后续需要用键来还原原始值时，可以通过解析前缀（如 `strncmp`）和值（如 `atoi`, `atof`）来实现。

### 3.6 可用的类型注解

下表列出了 PikaPython 支持的类型注解及其对应的 C 原生类型：

| Python 类型注解 | C 原生类型   | C 函数签名中的类型 | 说明                                  |
| :-------------- | :----------- | :----------------- | :------------------------------------ |
| `int`           | `int`        | `int`              | Python 基本类型                       |
| `int64`         | `int64_t`    | `int64_t`          | 64 位整型                             |
| `float`         | `pika_float` | `pika_float`       | Python 基本类型                       |
| `str`           | `char *`     | `char*`            | Python 基本类型                       |
| `bytes`         | `uint8_t *`  | `uint8_t*`         | Python 基本类型                       |
| `list`          | `PikaObj *`  | `PikaObj*`         | **注意：** 在C函数中接收为 `PikaObj*` |
| `dict`          | `PikaObj *`  | `PikaObj*`         | **注意：** 在C函数中接收为 `PikaObj*` |
| `tuple`         | `PikaObj *`  | `PikaObj*`         | **注意：** 在C函数中接收为 `PikaObj*` |
| `any`           | `Arg*`       | `Arg*`             | PikaPython 提供的泛型容器             |
| 任意 class      | `PikaObj *`  | `PikaObj*`         | PikaPython 提供的对象容器             |


## 4 测试脚本格式规范

### 4.1 结构与顺序（必须严格遵守）

1. 导入 & Python 基线函数：`import <module_name>`；定义 `py_xxx(...)`。

2. 功能测试：调用 C 模块与基线，比较。

3. **多样化测试数据**: 为了验证算法的通用性并防止硬编码，测试脚本**必须**包含至少两组独立的、合理的**常见输入数据**。测试应优先覆盖核心功能，可以不包含边界值或可能引发底层环境问题的奇异值（如`None` 等，除非任务明确要求）。例如：

   ```python
   # 第一组数据
   data1 = [3, 1, 5, 9, 2]
   # ... 对 data1 进行完整测试 ...
   # 第二组数据
   data2 = [10, 20, 30, 5, 15]
   # ... 再次对 data2 进行完整测试 ...
   ```

   只有当所有不同输入的测试都通过时，任务才被视为功能正确。

4. 仅当断言成功后再进行性能测试（4.2）。

5. 输出顺序：`[EXAMPLE]` -> `[PERF] python_total` -> `[PERF] cmod_total` -> `[PERF] speedup` -> `[EXAMPLE][SELFTEST]`。

### 4.2 性能测试准则

1. 不得在功能断言前计时。
2. 使用 `time.time()`；禁止使用复杂 profiling、ctypes、.so。
3. 典型结构：

```
ITER = 10000
# 计时 Python 基线
# 计时 C 模块
```

4. Speedup 计算：`speedup = py_mean / c_mean`。
5. 若功能断言失败，不输出任何 PERF 行。
6. **重要提醒**: 性能测试前必须确保所有功能测试通过。任何时候功能正确性都优先于性能优化。

## 5 运行与工具使用

### 5.1 允许写入路径（再声明）

仅限：模块目录 `.pyi` / `.c` 与 `./file_create/<session_path>/test_example.py`。

### 5.2 工具调用规则

1. 写文件：直接写入，父目录自动创建。
2. 读内容：只读具体文件，不读目录。
3. 执行：调用构建/运行命令一次。
4. 获取日志：成功解析后不重复读取整份日志。

### 5.3 构建命令重述

`python run_pika.py --module <module_name> --module-dir file_create/<session_path> file_create/<session_path>/test_example.py`

## 6 环境差异与限制

### 6.1 Python 语法子集限制 (重要)

PikaPython 仅支持 Python 语法的子集。在编写测试脚本 (`test_example.py`) 时，**必须**避免使用以下语法，否则会导致运行时错误：

* **禁止三元表达式**:

  * **错误**: `val = x / y if y != 0 else 0`

  * **正确**:

    ```python
    if y != 0:
        val = x / y
    else:
        val = 0
    ```

* **禁止 f-string**:

  *   **错误**: `print(f"value is {x}")` 或 `assert False, f"error {x}"`
  *   **正确**: `print("value is", x)` 和 `assert False, "error " + str(x)`

* **禁止多元赋值 (Tuple Unpacking)**:

  * **错误**: `a, b = 1, 2` 或 `mn, mx = min_max(data)`

  * **正确**:

    ```python
    a = 1
    b = 2
    # 对于函数返回元组
    min_max_val = min_max(data)
    mn = min_max_val[0]
    mx = min_max_val[1]
    ```

* **禁止使用迭代器 (`iter`/`next`)**:

  * **原因**: PikaPython 的 `for` 循环对迭代器的支持不完整，直接使用 `iter()` 和 `next()` 可能导致运行时错误或段错误。

  * **错误**:

    ```python
    it = iter(nums)
    first = next(it)
    for x in it:
        # ...
    ```

  * **正确**: 使用 `range` 和索引进行遍历。

    ```python
    # 正确的遍历方式
    if len(nums) == 0:
        return
    first = nums[0]
    for i in range(1, len(nums)):
        x = nums[i]
        # ...
    ```

* **禁止 `try...except Exception as e` 语法**:

  * **原因**: PikaPython 的 `try...except` 实现可能不完全支持 `as e` 语法来捕获异常对象。使用它可能导致 `NameError: name 'e' is not defined`。

  * **错误**:

    ```python
    try:
        # ... some code that might fail ...
    except Exception as e:
        print("An error occurred:", e)
    ```

  * **正确 (避障策略)**: 使用不带 `as e` 的 `except` 块来捕获异常，但这将无法获取异常对象的具体信息。

    ```python
    try:
        # ... some code that might fail ...
    except:
        print("An error occurred")
    ```

* **禁止带下划线的数字字面量**:

  *   **原因**: PikaPython 的解释器不支持 Python 3.6+ 引入的数字下划线分隔符。
  *   **错误**: `num = 1_000_000`
  *   **正确**: `num = 1000000`

* **禁止复杂的断言表达式**:

  * **原因**: PikaPython 的断言处理不支持复杂的布尔表达式，可能导致 `TypeError: exceptions must derive from BaseException`。

  * **错误**: `assert len(a) == len(b) == 0`

  * **正确**: 

    ```python
    assert len(a) == 0, "a should be empty"
    assert len(b) == 0, "b should be empty"
    ```

* 禁止 in 操作符用于字典:
  原因: 在 PikaPython 的 for 循环或 if 判断中直接使用 key in dict 不被支持，是导致 test_example.py 中基线函数 (py_...) 运行时抛出 KeyError 的最常见原因。

正确 (强制安全模式): 所有涉及字典计数或查询的基线函数，必须统一采用以下唯一安全模式：

``` python
# 初始化一个空字典
counts = {}
for i in range(len(data)):
    item = data[i]
    # 第一步：使用 .get() 获取当前计数，注意：必须检查是否为 None
    current_count = counts.get(item)
    if current_count is None:
        # 第二步：键不存在，设置初始值
        counts[item] = 1
    else:
        # 第三步：键存在，更新计数
        counts[item] = current_count + 1
```

* **禁止使用部分内置函数 (如 `sum()`)**:

  * **原因**: PikaPython 的标准库实现非常精简，不包含所有 Python 的内置函数，例如 `sum()`。这是导致运行时 `NameError: name 'sum' is not defined` 的最常见原因之一。

  * **错误**: `total = sum(my_list)`

  * **正确 (避障策略)**: 使用手动循环来实现相同的功能。

    ```python
    total = 0
    for x in my_list:
        total += x
    ```

  * **其他受限内置函数**: 包括但不限于 `max()`, `min()`, `abs()`, `round()` 等。遇到 `NameError` 时，首先检查是否使用了不支持的内置函数。

* **算法选择在受限环境下的权衡 (重要先验知识)**:

  *   **核心原则**: 在PikaPython受限环境下，实用性优先于理论最优。宁可选择时间复杂度较高的确定可行算法，也不要使用可能导致运行时崩溃的高效算法。
  *   **典型案例**: 对于计数类问题，优先使用双重循环手动计数（O(n²)），而非字典计数（可能触发 `KeyError` 或语法不支持）。
  *   **决策准则**: 如果标准Python实现依赖字典、复杂数据结构或高级语法，应主动寻求等价的简化实现，即使性能稍差。


#### 6.1.1 基线函数增量修复流程（强制）

当 `py_...` 基线在 PikaPython 环境下报错或结果异常时，必须执行以下小步迭代修复，不得跳过任一步骤、不得直接改用硬编码断言：

1. 最小化重现
   - 提取出最小输入数据（可将数据列表缩减到 2~3 个元素）触发同类错误。
   - 暂时注释掉与该函数无关的其他测试逻辑，聚焦单函数。
2. 语法收敛
   - 逐条检查 6.1 子集限制：去除 f-string、三元表达式、多元赋值、`key in dict`、`sum()`、`iter/next`、`try...except as e`、下划线数字等。
   - 若有字典计数逻辑，统一改为 `val = d.get(k); if val is None: d[k] = 1 else: d[k] = val + 1` 模式。
3. 结构简化
   - 将多层复合表达式拆解为逐行变量；避免一行内多逻辑（便于定位哪一行在裁剪解释器中失效）。
4. 逐步验证
   - 每次仅修改一个语法/逻辑点后立即重新运行构建与测试；出现新错误立即回退上一改动并改用更原子化拆分方式。
5. 扩展回归
   - 在最小数据通过后，恢复完整两组测试数据（4.1 要求），再次验证一致性。

#### 6.1.2 基线函数设计的“避障优先”原则

在编写 Python 基线函数 (py_...) 时，首要目标不是代码简洁或优雅，而是在 PikaPython 的受限环境中稳定运行。为此，必须遵循以下原则：

避免字典，除非必要：如果算法逻辑允许，优先考虑不使用字典的实现方式。例如可以采用双重循环手动计数（如本次实践后期的成功方案），虽然时间复杂度较高，但能100%规避字典相关的运行时陷阱。
内置函数黑名单：明确知晓并规避 PikaPython 不支持的内置函数。最常见的是 sum()。任何涉及聚合操作（求和、求积等）都必须使用手动循环实现。
结构极度扁平化：避免任何嵌套过深的逻辑、列表推导式、生成器表达式等。所有逻辑应拆解为最基础的 for 循环和 if-else 分支。
核心思想：当简洁性与兼容性冲突时，无条件选择兼容性。一个能在 PikaPython 中正确运行的“笨拙”基线函数，远胜于一个在标准 Python 中高效但无法运行的“优雅”函数。 


#### 6.1.3 案例经验教训与提醒

**前车之鉴**：在历史模块开发中，我们经历了从复杂方案失败到简化方案成功的完整过程。以下是关键教训：

*   **PikaPython环境限制补充**:
    *   禁止f-string、三元表达式、多元赋值、复杂断言、迭代器、部分内置函数（如sum、max、min、round、abs等）。
    *   print仅支持逗号分隔参数，禁止f-string和.format。
    *   字典不支持`key in dict`，必须用`dict.get(key)`并检查None。
    *   C端类型系统严格区分`Arg*`与`PikaObj*`，返回值类型必须与接口头文件一致。
    *   字符串返回必须用`obj_cacheStr()`，对象返回用`arg_newObj()`。
    *   列表元素类型需分支处理，不能直接用`getFloat`读取int。
    *   性能测试必须在功能断言全部通过后进行，避免无效数据。
    *   性能测试参数需根据环境实际调整，避免超时。
    *   复杂对象嵌套（如字典值为列表）需用`arg_newObj`包装，禁止用`setPtr`存指针。
    *   断言表达式复杂导致解析失败，需拆分为简单断言。
    *   所有函数入口优先处理空列表、None、越界等情况。
    *   任何硬编码、伪造逻辑都视为失败，禁止为通过测试而虚假实现。

*   **典型报错诊断经验补充**:
    *   `KeyError`：极大概率为基线函数用`key in dict`，需改为`dict.get(key)`模式。
    *   `NameError`：常见于sum、max等内置函数或f-string，需用手动循环或print分隔参数替代。
    *   `TypeError: exceptions must derive from BaseException`：断言表达式过于复杂，需拆分为简单断言。
    *   `Assertion "self != 0" failed`：C端未检查NULL指针，需在用`arg_getType`前加NULL判断。
    *   `arg type not support`：C端返回了原始指针或类型不符，需用`arg_newObj`包装对象。
    *   `conflicting types`编译错误：C函数返回类型与接口头文件不一致，需严格匹配。
    *   `undefined reference to 'arg_incRef'`：API不存在，需用类型构造函数如`arg_newInt`等。
    *   `incompatible pointer types`：`arg_newRef`参数类型错误，需用`arg_getPtr`或直接用`arg_newObj`。
    *   `ValueError: invalid literal for int()`：数字字面量带下划线，需去除。

*   **最佳实践与避障策略补充**:
    *   所有基线函数优先用最基础for循环和if-else，避免任何高阶语法。
    *   字典计数优先用双重循环替代，保证稳定性。
    *   调试时优先创建极简测试用例，逐步增量恢复。
    *   C端所有对象操作前必须做类型和NULL检查。
    *   遇到API不确定时，优先用`grep`在源码中查找。
    *   记录所有API用法和修复模式，形成知识库。

*   **主动调试与增量修复补充**:
    *   先实现最小可运行版本，逐步添加逻辑。
    *   每次修改后立即编译运行，遇错即回退。
    *   记录所有API用法和修复经验，形成知识库。

*   **代码探索黄金法则补充**:
    *   API不确定时，优先用`grep`在`pikapython-linux/pikapython/pikascript-core/PikaObj.h`查找。
    *   记录所有API用法和修复经验，形成知识库。

*   **API陷阱提醒**: 
    *   `arg_incRef()` 函数不存在，不要尝试使用。
    *   `arg_newRef()` 参数类型不匹配（期望 `PikaObj*`，非 `Arg*`）。
    *   返回 `Arg*` 时，必须使用 `arg_newInt()`、`arg_newFloat()`、`arg_newStr()` 等类型特定构造函数。

*   **语法限制再提醒**:
    *   `sum()` 函数会导致 `NameError`，必须用手动循环替代。
    *   在受限环境下，宁可选择 O(n²) 双重循环，也不要使用可能崩溃的字典方案。

*   **开发策略提醒**:
    *   遇到 API 不确定时，立即使用 `grep` 在源码中验证，而非猜测。
    *   编译错误时，从错误信息中学习正确 API，而非尝试"修复"错误信息。
    *   当标准算法不可行时，主动寻找等价的简化实现。

*   **质量把控提醒**:
    *   功能正确性优先于性能优化。
    *   任何"为了通过测试"的硬编码都是失败。
    *   多次失败后仍要坚持找到真正可行的方案。整个任务失败的最常见根源。宁可牺牲性能，也要保证基线函数的语法兼容性。

*   **基于案例的经验教训**:
    *   **字典操作的 KeyError 陷阱**: PikaPython 的字典不支持 `key in dict` 语法，会导致 `KeyError`。必须使用 `dict.get(key)` 模式并检查返回值是否为 `None`。
    *   **混合数据类型计数策略**: 当需要处理包含不同类型元素的列表时，使用类型前缀键策略（如 `"i_%ld"`、`"f_%.6f"`、`"s_%s"`）是最佳实践，可以完美解决字典键类型限制。
    *   **实用主义算法选择**: 在功能正确性和理论最优之间，无条件选择兼容性。宁可使用 O(n²) 双重循环计数，也不要使用可能导致运行时崩溃的字典方案。
    *   **编译警告处理**: 修复格式字符串类型不匹配（如 `%d` vs `%ld`）虽然不影响功能，但应及时处理以确保代码质量。
    *   **环境差异优先认识**: 开发前必须深刻理解 PikaPython 的限制，而非假设标准 Python 兼容性。字典操作、语法子集等都是常见陷阱。
    *   **测试断言简化原则**: 在测试脚本中避免复杂的布尔表达式断言（如 `assert len(py_norm_empty) == len(c_norm_empty) == 0`），优先使用简单断言以防 PikaPython 语法解析失败。
    *   **类型提取健壮性**: 在 C 代码中处理列表元素时，必须先检查 `arg_getType()` 再调用对应的 `arg_get*()` 函数，避免类型不匹配错误。
    *   **边界情况优先处理**: 空列表、None 值等边界情况应在核心逻辑前优先处理，确保函数鲁棒性。
    *   **性能测试隔离**: 功能断言全部通过后再进行性能测试，确保基准测试在相同环境下运行。

*   **PikaPython 核心限制与特性**:
    *   **精简标准库**: PikaPython 的标准库实现非常精简，不支持许多 Python 内置函数（如 `sum()`, `max()`, `min()`, `abs()`, `round()` 等）。遇到 `NameError` 时，首先检查是否使用了不支持的内置函数。
    *   **语法子集限制**: 仅支持 Python 语法的子集，禁止 f-string、三元表达式、多元赋值、迭代器操作等。所有逻辑必须拆解为最基础的 for 循环和 if-else 分支。
    *   **字典实现差异**: PikaPython 的字典实现与标准 Python 存在显著差异，不支持 `key in dict` 操作，必须使用 `dict.get(key)` 并检查返回值。
    *   **类型系统严格**: C 代码中必须严格区分 `Arg*`（通用容器）和 `PikaObj*`（具体对象），混淆会导致编译错误或运行时崩溃。
    *   **内存管理特殊**: 字符串返回必须使用 `obj_cacheStr()` 缓存，否则可能导致悬垂引用；对象返回必须使用 `arg_newObj()` 包装。
    *   **函数签名陷阱**: C 函数返回类型必须与接口头文件严格匹配。返回 `Arg*` 而接口期望 `PikaObj*` 会导致编译错误 "conflicting types"。
    *   **数据类型混合处理**: 当列表包含 `int` 和 `float` 时，必须在 C 代码中先检查 `arg_getType()` 再使用对应的提取函数，避免类型不匹配。
    *   **边界情况处理**: 空列表、None 值等边界情况必须在函数入口处优先处理，确保算法鲁棒性。
    *   **测试脚本兼容性**: 断言语句应避免复杂布尔表达式，优先使用简单比较以防 PikaPython 解析失败。

写入/覆盖 `./file_create/test_example.py`，结构与顺序必须完全符合 4.1 / 4.2 规范。

### 6.2 print 使用限制

仅使用逗号分隔参数：`print("value:", x)`；禁止 f-string / `.format()`，否则可能静默失效。

### 6.3 轻量运行时差异

标准库覆盖有限；如遇“无输出”或行为差异，应优先怀疑运行时裁剪。

## 7 调试与故障排查

### 7.1 Segmentation fault 增量定位策略

1. 极简化：缩减到 1 个最小可行函数（C 与测试同步精简）。
2. 验证基线：先确认最简版本可构建与运行。
3. 增量添加：一次添加一个小逻辑或函数。
4. 逐步测试：每次添加后立即构建 & 执行。如出现段错误，即定位于最近增量。

### 7.1.1 基于分析报告的诊断经验

*   **函数签名类型冲突诊断**:
    *   **现象**: 编译时出现 `error: conflicting types for 'function_name'; have 'Arg *(PikaObj *, PikaObj *)' but want 'PikaObj *(PikaObj *, PikaObj *)'`。
    *   **原因**: C 函数实现中的返回类型与接口头文件 (.pyi 生成的 .h 文件) 中声明的返回类型不匹配。通常是返回了 `Arg*` 但接口期望 `PikaObj*`，反之亦然。
    *   **诊断步骤**: 
        1. 检查生成的头文件中的函数声明。
        2. 对比 C 实现文件中的函数签名。
        3. 确认返回类型是否匹配（`PikaObj*` vs `Arg*`）。
    *   **修复模式**: 根据接口要求调整函数签名。对于返回对象的情况，使用 `PikaObj*` 并返回 `NULL` 表示 None；对于可能返回对象或 None 的情况，使用 `Arg*` 并用 `arg_newObj()` 包装对象。

*   **arg_newRef 参数类型不匹配诊断**:
    *   **现象**: 编译时出现 `error: incompatible pointer types` 或运行时崩溃。
    *   **原因**: `arg_newRef()` 函数期望接收 `PikaObj*` 类型，但传入的是 `Arg*` 类型。
    *   **诊断步骤**: 
        1. 检查所有 `arg_newRef()` 调用，确保参数是 `PikaObj*` 类型。
        2. 如果需要从 `Arg*` 转换为 `PikaObj*`，使用 `arg_getPtr()` 函数。
        3. 验证对象生命周期，确保返回的对象在函数作用域内有效。
    *   **修复模式**: `return arg_newRef(arg_getPtr(arg));` 而非直接 `return arg_newRef(arg);`。

*   **NULL 指针断言失败诊断**:
    *   **现象**: 运行时出现 `Assertion 'obj != NULL' failed` 或类似崩溃。
    *   **原因**: 在调用 `arg_getType()` 或其他需要有效对象的函数前，未检查对象是否为 NULL。
    *   **诊断步骤**:
        1. 检查所有 `arg_getType()` 调用前是否有 NULL 检查。
        2. 验证参数获取逻辑，确保 `arg_getPtr()` 返回值不为 NULL。
        3. 添加防御性编程：`if (NULL == obj) return arg_newNone();`。
    *   **修复模式**: 在所有对象操作前添加 NULL 检查。

*   **编译警告的系统性处理**:
    *   **格式字符串警告**: `%d` vs `%ld` 类型不匹配，虽然不影响功能，但应统一使用 `%ld`（long int）。
    *   **未使用变量警告**: 移除或注释掉未使用的变量声明。
    *   **隐式声明警告**: 确保所有函数都有正确的原型声明。
    *   **处理原则**: 即使警告不影响运行，也应及时修复以维护代码质量。

*   **性能验证的实用方法**:
    *   **基准测试**: 使用 `time.time()` 记录开始和结束时间，计算性能提升倍数。
    *   **正确性验证**: 确保 C 模块输出与 Python 基准完全一致。
    *   **渐进式优化**: 先实现功能正确，再追求性能优化。

### 7.2 错误输出格式

语法检查失败：`[ERROR] <描述>`
构建失败：`[BUILD_FAIL] <摘要>`
运行失败：`[RUN_FAIL] <摘要>`
成功：统一 `[MODULE]` 块（见第 8 节）。

### 7.2.1 运行时错误诊断经验：`arg type not support`

*   **错误场景**: 当你在 Python 测试脚本中对一个变量调用一个函数（例如 `len(my_var)`），但 PikaPython 运行时抛出 `[Error] len: arg type not support` 错误。
*   **核心原因**: 这几乎总是意味着 `my_var` 变量的**实际类型**与你**期望的类型**不符。最常见的情况是：
    1.  你期望它是一个列表 (`list`)、字典 (`dict`) 或其他可迭代对象。
    2.  但它实际上是一个整数 (`int`)、指针地址 (`0x...`) 或其他不支持该操作的类型。
*   **诊断步骤**:
    1.  **确认来源**: 这个变量是从哪里来的？如果它来自 C 模块的返回值，那么问题几乎可以 100% 定位到 C 模块的实现上。
    2.  **检查 C 实现**:
        *   **指针陷阱**: 你是否在 C 代码中错误地返回了一个**原始指针**而不是一个**PikaPython 对象**？
        *   **常见案例**: 在字典中存储列表时，错误地使用了 `pikaDict_setPtr()` 而不是 `pikaDict_set(..., arg_newObj(...))`。前者只存了地址，导致 Python 端收到了一个整数，从而在调用 `len()` 时报错。
    3.  **验证策略**: 在 Python 测试脚本中，直接 `print()` 这个出问题的变量。如果你看到的是一个 `0x...` 格式的地址，那么就可以完全确定是 C 端的对象包装出了问题。
*   **解决方向**: **不要**试图在 Python 测试脚本中“修复”这个问题（例如，尝试转换类型）。**必须**回到 C 源代码，使用正确的 API（如 `arg_newObj`）来包装和返回对象。

### 7.2.2 运行时错误诊断经验：`IndexError: index out of range`

*   **错误场景**: 在 `test_example.py` 运行时，出现 `IndexError: index out of range`。
*   **核心原因**: 这通常不是 C 模块的问题，而是 **Python 基线测试函数** (`py_...`) 在 PikaPython 的受限运行环境中出现了问题。PikaPython 对 Python 语法的支持是子集，一些在标准 Python 中合法的操作（特别是涉及字典和迭代器）可能会失败。
*   **诊断步骤**:
    1.  **定位错误源**: 确认错误发生在 Python 代码 (`test_example.py`) 中，而不是 C 模块的执行。
    2.  **检查语法限制**: 回顾 Python 基线函数的实现，检查是否使用了 PikaPython 不支持或行为不一致的语法，例如 `key in dict`。
*   **解决方向**:
    *   **唯一允许路径：修正 Python 基线函数**。按照 6.1 与 6.1.1 的子集与增量修复流程进行最小化、拆分、验证。禁止改用硬编码常量绕过基线逻辑。
    *   如在严格执行 6.1.1 七步后仍无法稳定（连续 3 次迭代失败），应终止并报告 `[DEGRADED_SEMANTICS]`，而非跳过基线。

### 7.2.3 运行时错误诊断经验：`Assertion "self != 0" failed`

* **错误场景**: C 模块执行时，程序因 `Aborted` 退出，日志显示 `Assertion "self != 0" failed, in function: arg_getType()`。

* **核心原因**: 这是一个**空指针断言失败**。它意味着一个 `NULL` 指针被传递给了 `arg_getType()` 函数，而该函数期望一个有效的 `Arg*` 参数。这几乎总是由 `pikaDict_get()` 或 `pikaList_get()` 等查找函数在**未找到**指定内容时返回 `NULL`（而不是一个 `ARG_TYPE_NONE` 的 `Arg*` 对象）引起的。

* **诊断步骤**:

  1.  **定位来源**: 找到日志中失败的 `arg_getType()` 调用在 C 源码中的位置。
  2.  **追溯上游**: 查看被传入 `arg_getType()` 的那个 `Arg*` 变量是从哪里获取的。大概率是来自一个 `pikaDict_get()` 或 `pikaList_get()` 的调用。
  3.  **确认问题**: 这表明上游的查找操作失败了（例如，字典中不存在该键），并且其返回的 `NULL` 值未经检查就直接被使用了。

* **解决方向**: **必须**在使用 `pikaDict_get()` 或 `pikaList_get()` 的返回值之前，添加一个 `NULL` 指针检查。

  ```c
  // 错误：未检查 pikaDict_get 的返回值
  Arg* count_arg = pikaDict_get(counts, key);
  if (arg_getType(count_arg) == ARG_TYPE_NONE) { // 如果 count_arg 是 NULL，这里会崩溃
      // ...
  }
  
  // 正确：在使用前进行 NULL 检查
  Arg* count_arg = pikaDict_get(counts, key);
  if (count_arg == NULL) { // 键不存在，返回了 NULL
      // 处理键不存在的情况，例如设置初始值
      pikaDict_setInt(counts, key, 1);
  } else {
      // 键存在，可以安全地使用 count_arg
      int current_count = arg_getInt(count_arg);
      pikaDict_setInt(counts, key, current_count + 1);
  }
  ```

### 7.2.4 运行时错误诊断经验：`KeyError`

*   **错误场景**: 在 `test_example.py` 运行时，出现 `KeyError`，尤其是在访问字典时。
*   **核心原因**: 这**极大概率**与 `py_...` 基线函数中的字典操作有关，特别是当使用了 PikaPython 不支持的 `in` 操作符时。PikaPython 的 `dict` 实现与标准 Python 存在差异，导致 `in` 关键字的行为不符合预期。
*   **诊断步骤**:
    1.  **定位错误源**: 确认错误发生在 Python 代码 (`test_example.py`) 中。错误日志通常会指向 `py_...` 函数中的某一行。
    2.  **检查语法限制**: 立即检查该行或附近代码是否使用了 `if key in dict:` 语法。
*   **解决方向**:
    (1) 强制修复: 立即使用 val = dict_obj.get(k) 模式替代 k in dict_obj。
    (2) 主动规避 (推荐): 如果修复后问题依然存在或逻辑过于复杂，应果断放弃字典方案，重构基线函数为不依赖字典的纯列表操作（如双重循环计数）。这是本次实践中验证过的、最可靠的终极解决方案。
    (3) 严禁为了绕过此错误而直接与硬编码常量进行比较。

### 7.2.5 运行时错误诊断经验：`ValueError: invalid literal for int()`

*   **错误场景**: 在 `test_example.py` 运行时，出现 `ValueError: invalid literal for int()`，尤其是在处理数字时。
*   **核心原因**: 这通常是由于在 Python 代码中使用了 PikaPython 不支持的数字格式。
*   **诊断步骤**:
    1.  **定位错误源**: 确认错误发生在 Python 代码 (`test_example.py`) 中。
    2.  **检查语法限制**: 检查是否使用了带下划线的数字字面量（如 `1_000_000`）。
*   **解决方向**:
    *   **修正 Python 代码**: 移除数字中的下划线（例如，将 `1_000_000` 改为 `1000000`）。

### 7.2.6 运行时错误诊断经验：`NameError`

*   **错误场景**: 在 `test_example.py` 运行时，出现 `NameError: name 'xxx' is not defined`。
*   **核心原因**: 这通常意味着你使用了 PikaPython 的精简运行时所不支持的：
    1.  **内置函数**: 例如 `sum`。
    2.  **语法结构**: 例如 f-string (`f"..."`)，它在 PikaPython 中被当作一个普通的变量名，从而导致 `NameError`。
*   **诊断步骤**:
    1.  **定位错误源**: 确认错误发生在 Python 代码 (`test_example.py`) 中。
    2.  **检查名称 `xxx`**:
        *   如果 `xxx` 是一个函数（如 `sum`），说明它不被支持。
        *   如果 `xxx` 看起来像一个 f-string（如 `f"Test failed..."`），说明 f-string 语法不被支持。
*   **解决方向**:
    *   **替换或手动实现**: 将不支持的函数（如 `sum()`）替换为手动循环。
    *   **使用兼容语法**: 将 f-string 替换为 `print()` 的多参数形式和 `if` 判断。

### 7.2.7 编译错误诊断经验：`undefined reference to 'arg_incRef'`

* **错误场景**: 编译时出现 `undefined reference to 'arg_incRef'` 或类似 "implicit declaration" 警告。

* **核心原因**: 尝试使用了不存在的API函数。PikaPython的API可能与预期不符，某些函数名不存在或签名不同。

* **诊断步骤**:

  1.  **检查函数名**: 确认是否使用了正确的API。`arg_incRef` 不存在，应使用类型特定的构造函数。
  2.  **查找替代方案**: 使用 `grep` 在头文件中搜索相关API，或参考现有成功案例。

* **解决方向**:

  * **使用类型构造函数**: 不要尝试引用现有对象，而是创建新的：

    ```c
    // 错误
    return arg_incRef(existing_arg);
    
    // 正确
    if (arg_getType(existing_arg) == ARG_TYPE_INT) {
        return arg_newInt(arg_getInt(existing_arg));
    }
    ```

### 7.2.8 运行时错误诊断经验：`incompatible pointer types` (arg_newRef)

*   **错误场景**: 编译时出现 `passing argument 1 of 'arg_newRef' from incompatible pointer type` 警告，或运行时段错误。
*   **核心原因**: `arg_newRef` 期望 `PikaObj*` 参数，但传递了 `Arg*` 类型。API参数类型不匹配导致的类型错误。
*   **诊断步骤**:
    1.  **检查参数类型**: 确认传递给API函数的参数类型是否正确。
    2.  **理解Arg vs PikaObj**: `Arg*` 是通用容器，`PikaObj*` 是具体对象。混淆这两种类型是常见错误。
*   **解决方向**:
    *   **避免arg_newRef**: 该函数可能不适合直接返回Arg对象。改用类型特定的构造函数或 `arg_newObj()` 包装PikaObj。

### 7.2.9 编译错误诊断经验：`format '%d' expects argument of type 'int', but argument has type 'int64_t'`

*   **错误场景**: 编译时出现 `format '%d' expects argument of type 'int', but argument has type 'int64_t'` 警告。
*   **核心原因**: 在 C 代码中使用 `snprintf` 或 `printf` 时，格式说明符与实际参数类型不匹配。PikaPython 中某些值可能是 `int64_t` 类型，但使用了 `%d` 而非 `%ld`。
*   **诊断步骤**:
    1.  **检查格式字符串**: 找到出现警告的 `snprintf` 调用。
    2.  **确认参数类型**: 检查传递的参数是否为 `int64_t` 或其他 64 位类型。
*   **解决方向**:
    *   **使用正确的格式说明符**: 对于 `int64_t` 使用 `%ld`，对于 `double` 使用 `%.6f` 等。
    *   **类型转换**: 如有必要，使用 `(long)` 或 `(int)` 进行显式转换。

### 7.2.10 运行时错误诊断经验：`KeyError` (字典操作)

*   **错误场景**: 在 `test_example.py` 运行时，出现 `KeyError`，尤其是在访问字典时。
*   **核心原因**: 这**极大概率**与 `py_...` 基线函数中的字典操作有关，特别是当使用了 PikaPython 不支持的 `in` 操作符时。PikaPython 的 `dict` 实现与标准 Python 存在差异，导致 `in` 关键字的行为不符合预期。
*   **诊断步骤**:
    1.  **定位错误源**: 确认错误发生在 Python 代码 (`test_example.py`) 中。错误日志通常会指向 `py_...` 函数中的某一行。
    2.  **检查语法限制**: 立即检查该行或附近代码是否使用了 `if key in dict:` 语法。
*   **解决方向**:
    (1) 强制修复: 立即使用 `val = dict_obj.get(k); if val is None: ...` 模式替代 `k in dict_obj`。
    (2) 主动规避 (推荐): 如果修复后问题依然存在或逻辑过于复杂，应果断放弃字典方案，重构基线函数为不依赖字典的纯列表操作（如双重循环计数）。这是本次实践中验证过的、最可靠的终极解决方案。
    (3) 严禁为了绕过此错误而直接与硬编码常量进行比较。

### 7.3 主动代码探索黄金法则 (`grep` 的妙用)

当你对 API 的具体名称、参数或用法不确定时，**强烈鼓励**你使用 `grep` 等命令行工具直接在项目源代码中进行探索。这是一种比被动查阅文档更高效、更准确的方法。

* **适用场景**:

  *   遇到“未定义引用 (undefined reference)”或“隐式声明 (implicit declaration)”编译错误。
  *   不确定某个功能的 API 函数名（例如，是 `pikaList_len`, `pika_list_len` 还是 `pika_list_length`）。
  *   想要查找某个宏或类型的定义。

* **黄金操作范例**:

  1. **定位核心头文件**: PikaPython 的绝大多数核心 API 都定义在 `pikapython-linux/pikapython/pikascript-core/PikaObj.h`。

  2. **使用 `grep` 精准搜索**:

     ```bash
     # 示例：当不确定列表长度函数的准确名称时，
     # 搜索包含 "pikaList" 和 "len" 的行
     grep -n "pikaList" ./pikapython-linux/pikapython/pikascript-core/PikaObj.h | grep "len"
     
     # 示例：宽泛地搜索与 "pikaList" 相关的所有 API
     grep -n "pikaList" ./pikapython-linux/pikapython/pikascript-core/PikaObj.h | head -20
     ```

* **核心价值**: 这种方法能让你**自主发现**最准确、最新的 API 用法，减少因信息不全或规则遗漏导致的错误重试，是成为高级问题解决者的关键一步。

### 7.4 语义完整性原则与退化报告

*   **首要原则**: 你的核心目标是生成**语义正确**的 C 模块。任何形式的硬编码、占位符或伪造逻辑（即为了通过测试而返回固定值）都等同于任务失败。
*   **退化报告**: 如果你因知识限制或 API 障碍而无法实现完整的、正确的逻辑，**严禁**提交虚假实现。
*   **成功判定**: 任何包含 `[DEGRADED_SEMANTICS]` 标签的会话都**不会**被判定为成功。

### 7.5 主动调试最佳实践

除了被动地响应错误，更高效的策略是主动采用系统性的调试方法来快速定位问题。

* **实践一：创建小型、独立的测试用例**

  *   **场景**: 当一个复杂的测试用例失败时，很难确定是哪个输入或逻辑分支导致了问题。
  *   **策略**: 不要直接在原始的 `test_example.py` 中反复修改。创建一个新的、临时的 Python 文件（例如 `debug_test.py`），在其中只包含最简单的代码来复现问题。
  *   **步骤**:
      1.  **隔离**: 从复杂的输入数据中提取出能触发 bug 的最小子集。
      2.  **简化**: 编写一个只调用问题 C 函数的极简 Python 脚本。
      3.  **运行**: 使用 `python run_pika.py` 独立运行这个调试脚本。
  *   **优势**: 这种方法可以快速验证关于 bug 的假设，排除干扰因素，并显著加快定位速度。

* **实践二：在 C 代码中打印中间变量**

  * **场景**: 当 C 模块的最终输出不符合预期（例如，返回了 `None`、错误的计数值或空列表），但程序没有崩溃时。

  * **策略**: 在 C 函数的关键逻辑点，使用 `printf` 打印出中间变量的值。这可以让你清晰地追踪算法的执行流程和数据状态。

  * **步骤**:

    1. **包含头文件**: 确保 C 文件顶部有 `#include <stdio.h>`。

    2. **植入打印语句**: 在循环内部、条件判断分支、返回值之前等关键位置添加 `printf`。为了方便在日志中识别，可以加上特殊前缀。

       ```c
       // 示例：在循环中打印计数值
       printf("[DEBUG] Key: %s, Current Count: %d\n", key, current_count);
       ```

    3. **重新构建和运行**: 执行 `python run_pika.py ...`。

    4. **分析日志**: 在 `compile.log`（如果 `printf` 导致编译错误）或 `run.log` 中查找你的 `[DEBUG]` 输出，观察变量的变化是否符合预期。

  * **注意**: 调试完成后，应移除或注释掉这些 `printf` 语句。

* **实践三：API学习与错误驱动开发**

  *   **场景**: 对PikaPython API不熟悉，导致多次编译和运行时错误。
  *   **策略**: 采用渐进式API探索，从错误信息中学习正确的用法。
  *   **步骤**:
      1.  **从简单开始**: 先实现最基本的逻辑，使用已知可行的API。
      2.  **错误驱动学习**: 当遇到编译错误时，不要猜测，而是使用 `grep` 在源码中查找正确API。
      3.  **小步验证**: 每次只尝试一个新的API调用，立即编译验证。
      4.  **记录模式**: 将学到的API模式记录下来，避免重复犯错。
  *   **关键教训**: 
      *   不要假设API的存在性，总要验证。
      *   `arg_incRef`/`arg_newRef` 等看似合理的函数可能不存在。
      *   返回值必须使用类型特定的构造函数，而非对象引用。

* **实践四：算法选择在受限环境下的实用主义**

  *   **场景**: 标准算法在PikaPython中不可行，需要寻找替代方案。
  *   **策略**: 优先选择确定可行的算法，即使时间复杂度较高。
  *   **决策框架**:
      1.  **评估限制**: 检查算法是否依赖不支持的特性（字典、复杂语法等）。
      2.  **寻找替代**: 为高风险组件寻找等价的简化实现。
      3.  **性能权衡**: 在功能正确性和性能之间，选择前者。
  *   **成功案例**: 用双重循环计数替代字典计数，虽然O(n²)但保证稳定运行。

* **实践五：类型前缀键策略处理混合数据类型**

  * **场景**: 需要在 C 代码中对包含不同数据类型的列表进行计数或分组。

  * **策略**: 使用带类型前缀的字符串键来处理混合数据类型。

  * **实现模式**:

    ```c
    char key[128] = {0};
    if (arg_getType(item_arg) == ARG_TYPE_INT) {
        snprintf(key, sizeof(key), "i_%ld", (long)arg_getInt(item_arg));
    } else if (arg_getType(item_arg) == ARG_TYPE_FLOAT) {
        snprintf(key, sizeof(key), "f_%.6f", arg_getFloat(item_arg));
    } else if (arg_getType(item_arg) == ARG_TYPE_STRING) {
        snprintf(key, sizeof(key), "s_%s", arg_getStr(item_arg));
    }
    ```

  * **优势**: 完美解决 PikaPython 字典键必须是字符串的限制，支持混合类型处理。

* **实践六：渐进式环境适应**

  *   **场景**: 初次接触 PikaPython 限制，导致多次试错。
  *   **策略**: 采用渐进式方法，先实现基础功能，再逐步优化。
  *   **步骤**:
      1.  **环境认知**: 首先深入了解 PikaPython 的语法子集和 API 限制。
      2.  **最小化实现**: 从最简单的算法开始，确保能稳定运行。
      3.  **增量优化**: 在保证功能正确的前提下，逐步改进性能。
      4.  **边界测试**: 特别关注空输入、边界条件等易出问题的情况。
  *   **关键原则**: 功能正确性永远优先于性能优化。

* **实践七：类型安全的数据提取模式**

  * **场景**: 在 C 代码中处理 Python 列表元素时，需要安全地提取 `int` 和 `float` 值。

  * **策略**: 建立标准化的类型检查和提取模式，避免类型不匹配错误。

  * **实现模式**:

    ```c
    // 标准化的元素处理模式
    pika_float value = 0.0;
    if (arg_getType(element) == ARG_TYPE_INT) {
        value = (pika_float)arg_getInt(element);
    } else if (arg_getType(element) == ARG_TYPE_FLOAT) {
        value = arg_getFloat(element);
    } else {
        // 处理不支持的类型或返回错误
        return arg_newNone();
    }
    ```

  * **优势**: 确保类型安全，避免运行时崩溃，并提供清晰的错误处理。

* **实践八：边界情况优先设计**

  * **场景**: 忘记处理空列表、None 值等边界情况，导致运行时错误。

  * **策略**: 在函数开始处优先检查边界情况，确保核心逻辑只处理有效输入。

  * **实现模式**:

    ```c
    // 边界情况优先处理
    int len = pikaList_getSize((PikaList*)nums);
    if (len == 0) {
        // 直接返回适当的默认值
        return arg_newNone(); // 或空列表等
    }
    // 然后处理正常情况
    ```

  * **优势**: 简化核心逻辑，提高代码可读性和鲁棒性。

* **实践九：性能测试的隔离原则**

  *   **场景**: 功能测试失败时仍进行性能测试，导致无效的性能数据。
  *   **策略**: 严格隔离功能验证和性能测试，确保性能基准建立在正确实现之上。
  *   **实施要点**:
      1. 所有功能断言通过后再开始性能测试。
      2. 使用相同的输入数据进行 Python 基线和 C 模块测试。
      3. 记录详细的计时信息，便于问题诊断。
  *   **关键提醒**: 性能优化永远不能牺牲功能正确性。

## 8 输出格式定义

成功时：

```
[MODULE] <module_name>
[OUTPUT]
<关键运行输出行：EXAMPLE / PERF / SELFTEST>
[END]
```

（本文件可迭代优化，但需保持编号体系与单一语义来源，不再重复定义。）

