diff --git a/CHANGELOG.md b/CHANGELOG.md index e9da474..555a7bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ `repr` 紧凑单行且不打印 `data` 内容;`summary()` 输出可直接贴进论文的 Markdown 表格。 ### Added +- `docs/02-architecture.md` §4.7「类型约定」:注解要写全、numpy 标量的判断写法、 + 非法类型必须抛 `TypeError`。配套在 `docs/03-roadmap.md` 的开发纪律里加了指针。 - `docs/dev/personal-pitfalls.md`:个人易错点清单,**只追加、不通读** ### Notes diff --git a/docs/02-architecture.md b/docs/02-architecture.md index 6af6147..1d9ed3b 100644 --- a/docs/02-architecture.md +++ b/docs/02-architecture.md @@ -158,6 +158,31 @@ class Model(Protocol): **可选依赖缺失时必须给出可读报错**,例如 `sobol_analyze` 在没装 SALib 时提示 `pip install "mcm-toolkit[sensitivity]"`,而不是 `ModuleNotFoundError` 裸抛。 + +### 4.7 类型约定(每个函数都适用) + +公开函数的**参数类型注解必须写全**,并且与 docstring 说的是同一件事:注解给 IDE / pyright 看, +docstring 给人看。两处打架时,合法用法会被标红,真正的错误反而看不见。 + +判断顺序照抄下表,**不要凭直觉**: + +| 值可能来自 | 怎么写 | 为什么 | +|---|---|---| +| 整数 | `isinstance(x, (int, np.integer))`,取值统一 `int(x)` | `np.int64` **不是** `int` 的子类,只写 `int` 会漏 | +| 浮点 | `isinstance(x, (float, np.floating))` | `np.float64` 是 `float` 子类,但 `np.float32` 不是——不统一 | +| 布尔 | `isinstance(x, bool)` 要放在 `int` 判断**之前** | `True` 也是 `int`,顺序反了会当成 1 | +| 数组 / 表 | `np.asarray(x, dtype=float)` 后再校验 | 别假设调用方已经转好类型 | + +**非法类型必须 `raise TypeError`,不许静默兜底。** 静默的典型后果是 +"种子被忽略、结果不可复现,但没有任何提示"——比直接报错难查一百倍。 + +配套要求,每个公开函数都要有: + +- `Parameters` 写清类型与含义;允许 `None` 时,写明 `None` 会走哪条分支 +- `Raises` 写清会抛什么异常 + +参考实现:`core/random.py` 的 `get_rng`。 + --- ## 五、测试策略 diff --git a/docs/03-roadmap.md b/docs/03-roadmap.md index 6e7f93c..d8497cd 100644 --- a/docs/03-roadmap.md +++ b/docs/03-roadmap.md @@ -86,6 +86,7 @@ 1. 先想"这道题里它替代了哪段手写代码"——想不出来就先不写。 2. 先在 `tests/` 里写一条会失败的断言(测已知解析解,不测实现细节)。 + - 参数类型注解按 `02-architecture.md` §4.7 写全;非法类型抛 `TypeError`,不静默兜底。 3. 实现到测试通过。 4. 在 `examples/` 里加一行最小用法。 5. 更新 `STATUS.md`。