首页
/ ECC 的 Python 模式规则:用 Protocol、Dataclass DTO 与资源管理塑造 Agent 可执行的 Python 编码规范

ECC 的 Python 模式规则:用 Protocol、Dataclass DTO 与资源管理塑造 Agent 可执行的 Python 编码规范

2026-09-06 18:50:45作者:房伟宁

导读:本文将围绕 ECC(Everything Claude Code)仓库中面向 Kiro/ECC 环境的 Python 模式 steering 文件展开,说明它是如何在 AI Agent 编辑 *.py 文件时被自动加载、并将若干 Python 惯用模式固化为可执行编码规则的。读完本文,你将理解结构化鸭子类型(Protocol)、Dataclass DTO、上下文管理器与生成器这几组 Python 核心模式在 Agent 协作开发中的落地方式,并能在自己的 Kiro/Claude Code/Codex 项目中复用这套"规则 + skill + hook"的分层设计。

一、先认清这份文件的角色:一份按需注入的 Python 模式规则

在 ECC 仓库根目录的 .kiro 组件集中,.kiro/steering/python-patterns.md 属于 steering file(方向性规则文件) 的一员。依据 .kiro/README.md 的说明,steering file 提供"始终在线的规则与上下文",用来塑造 Agent 处理代码的方式,其中按加载策略分为三种:

  • inclusion: auto:每次对话都自动加载(如 coding-stylepatterns);
  • inclusion: fileMatch:仅在匹配到特定文件扩展名/路径时加载;
  • inclusion: manual:通过 #dev-mode#review-mode 等指令手动触发。

本文件即第二种的典型代表。它的 YAML frontmatter 明确写入了注入条件:

---
inclusion: fileMatch
fileMatchPattern: "*.py"
description: Python patterns extending common rules
---

也就是说,当 Agent(Kiro IDE/CLI 中的 AI 助手)正在编辑或审查 .py 文件时,这份 Python 专属模式规则才进入上下文;处理 TypeScript、Go 等其他语言时则由各自的 steering 文件接管(例如 .kiro/steering/typescript-patterns.md.kiro/steering/golang-patterns.md)。这种"语言匹配才注入"的机制,目的就是避免通用规则与 Python 专属约束相互干扰,同时把不必要的上下文负担降到最低

文件开头的一句话点明了它在规则体系中的定位:

This file extends the common patterns rule with Python specific content.

也就是说,它不是独立王国,而是对通用模式规则的 Python 方言扩展。与之对应的通用规则在仓库中有两份同源副本:Kiro 侧位于 .kiro/steering/patterns.mdinclusion: auto),ECC 主规则侧位于 rules/common/patterns.md;而 Kiro 版之外,ECC 主规则仓库内也保存了几乎同内容的 Python 规则版本 rules/python/patterns.md,并声明 paths: ["**/*.py", "**/*.pyi"]。对比这两份文件可以看出,.kiro/steering/python-patterns.md 只是把同一套模式内容适配成 Kiro 的 frontmatter 格式,正文与 rules/python/patterns.md 保持一致——这正体现了 ECC"同一套规则、多 harness 适配"的工程做法。

二、Protocol(鸭子类型):用结构子类型替代继承耦合

steering 文件给出的第一组 Python 模式是"Protocol(Duck Typing)":

from typing import Protocol

class Repository(Protocol):
    def find_by_id(self, id: str) -> dict | None: ...
    def save(self, entity: dict) -> dict: ...

这是一段**结构子类型(structural subtyping)**声明:只要一个类具备 find_by_idsave 两个同签名方法,即便它没有继承任何基类,也被视为满足 Repository 契约。对比传统的 ABC + abstractmethod(名义子类型,必须显式继承),Protocol 的优势在于:

  • 类型安全但不引入继承树:调用方(如业务服务)只需声明依赖 Repository 类型,静态检查器(mypy、pyright)即可校验传入对象是否满足接口;
  • 解耦存储实现:无论底层是数据库、HTTP API 还是内存字典,只要实现对应方法就能被注入;
  • 测试友好:在测试中可用轻量伪对象直接替换真实实现,无需 Mock 复杂继承链。

这段示例同时呼应了通用规则 rules/common/patterns.md 中"Repository Pattern"的定义——标准操作(findAll、findById、create、update、delete)收敛到一致接口、业务逻辑依赖抽象接口而非存储机制。二者放在一起读,才能看出 ECC 的思路:通用层定义"仓库模式该长什么样",Python 层定义"用 typing.Protocol 把它表达出来"

更完整的落地示例可以在配套 skill .kiro/skills/python-patterns/SKILL.md 中看到,它补充了"任何具有这些方法的类都满足协议"的实现类、泛型化 Repository(Generic[T]) 以及基于 Protocol 的构造器注入写法(UserService.__init__(self, repository: Repository, ...))。

三、Dataclasses as DTOs:用数据类承载传输对象

steering 文件的第二组模式把 dataclass 定位为 DTO(数据传输对象)与值对象的标准载体:

from dataclasses import dataclass

@dataclass
class CreateUserRequest:
    name: str
    email: str
    age: int | None = None

要点解析:

  • @dataclass 自动生成 __init____repr____eq__,让"定义数据结构 + 字段类型"成为唯一需要手写的部分;
  • 字段类型注解即文档:age: int | None = None 表示年龄为可选的整型,缺省值为 None
  • DTO 定位意味着它只做数据搬运,不承载业务行为,避免在 API 边界上泄露领域模型。

在 ECC 仓库自身代码中,这一模式有非常直观的运用。位于 src/llm/core/types.py 的 LLM 抽象层类型定义大量使用 frozen dataclass@dataclass(frozen=True)),例如 MessageToolDefinitionfrozen=True 让实例不可变,天然具备哈希与线程安全语义,这与 rules/python/coding-style.md 中"优先不可变数据结构"(推荐 frozen=True dataclass 与 NamedTuple)的规则完全一致,形成"规则书写 → 仓库代码印证"的闭环。

若需要可变集合默认值或复杂默认值,skill 层给出了更完整的进阶写法:

from dataclasses import dataclass, field

@dataclass
class CreateUserRequest:
    name: str
    email: str
    age: int | None = None
    tags: list[str] = field(default_factory=list)

@dataclass(frozen=True)
class User:
    """Immutable user entity"""
    id: str
    name: str
    email: str

其中 field(default_factory=list) 规避了"可变默认参数"这一经典 Python 反模式,frozen=True 则把 DTO 升级为不可变值对象;若需要校验,可在 __post_init__ 中执行 email 格式与年龄范围检查(详见 skill 中"Dataclasses with Validation"一节)。

四、Context Managers 与 Generators:资源管理与惰性迭代的两条铁律

steering 文件用两条精炼规则收束了 Python 资源管理的核心哲学:

  • 使用上下文管理器(with 语句)进行资源管理;
  • 使用生成器实现惰性求值与内存高效的迭代。

这两条看似简短,实则是 Python 中最能影响正确性与内存占用的一组决策。展开看:

上下文管理器让资源释放无法被遗漏。 最典型的对照是文件读取:

# 正确:无论是否抛异常,with 块退出都会关闭文件
with open(path, 'r') as f:
    return f.read()

# 错误:异常路径下可能泄漏文件句柄
f = open(path, 'r')
try:
    return f.read()
finally:
    f.close()

对于更复杂的"要么全成功要么全回滚"语义,.kiro/skills/python-patterns/SKILL.md 提供了基于 @contextmanager 的事务式上下文管理器——yield 之后的代码块充当 finally,出错时回滚并重新抛出异常:

from contextlib import contextmanager
from typing import Generator

@contextmanager
def database_transaction(db) -> Generator[None, None, None]:
    """Context manager for database transactions"""
    try:
        yield
        db.commit()
    except Exception:
        db.rollback()
        raise

with database_transaction(db):
    db.execute("INSERT INTO users ...")

生成器把"一次性读入全量"变为"按需逐条产出"。 处理大文件或大结果集时,这是内存差异巨大的两种写法:

# 惰性逐行读取,内存占用与文件大小无关
def read_large_file(path: str) -> Iterator[str]:
    with open(path) as f:
        for line in f:
            yield line.strip()

# 生成器表达式实现惰性求值(对比 list comprehension 会构造上百万元素的中间列表)
total = sum(x * x for x in range(1_000_000))

生成器还能组合成数据管道——前一个生成器的产出作为后一个的输入,全程不产生中间大列表(见 skill 的 Pipeline pattern 示例)。这一组合与 ECC 面向长流水线、资源受限的 harness 执行场景高度契合。

五、Reference:一条规则如何"向上收敛、向下授权"

steering 文件结尾的 Reference 段落值得单独解读:

See skill: python-patterns for comprehensive patterns including decorators, concurrency, and package organization.

这是一次明显的职责划分

  • steering/rules 层只保留最高频、最需要"每时每刻都提醒 Agent"的少量模式(Protocol、dataclass DTO、上下文管理器与生成器),避免常驻上下文过载;
  • 完整模式目录交给按需调用的 skillpython-patterns skill 在仓库中有两个可用副本——Kiro 侧 .kiro/skills/python-patterns/SKILL.md 与 ECC 主技能集 skills/python-patterns/SKILL.md,声明按 **/*.py**/*.pyi 匹配。skill 中覆盖了 steering 文件未展开的纵深主题:
主题类别 skill 中提供的具体内容
类型系统 TypeVar/Generic/ParamSpec 泛型、str | int | None 联合类型(Python 3.10+)、类型别名 JSON
装饰器 functools.wraps 保元数据、参数化装饰器 @repeat(times=3)、类装饰器与单例、类型安全日志装饰器
并发 ThreadPoolExecutor(I/O 密集)、ProcessPoolExecutor(CPU 密集)、asyncio.gather 与异步上下文管理器
错误处理 自定义异常层级(DomainError → 子类)、raise ... from e 异常链、Python 3.11+ except* Exception Groups
包组织 src/ 布局、domain/services/infrastructure 分层、__init__.py 显式导出与 __all__
面向对象进阶 @property 读写控制、构造器注入式依赖注入
性能与内存 __slots__ 减少内存占用、循环内字符串拼接改用 "".join()、StringIO

因此,一套完整的 Python 模式体系在 ECC 中是这样协同的:通用层rules/common/patterns.md)定设计原则 → Python 规则层(本文主题文件与 rules/python/patterns.md)给最高频 Python 表达 → skill 层skills/python-patterns/SKILL.md)提供按需查阅的全量模式库 → hook 层在编辑时提醒 Agent 落实。四个层次按上下文代价递增、触发频率递减排列。

六、规则之外:让 Agent 真正"照章办事"的配套机制

模式规则只有在被 Agent 实际执行时才产生价值。ECC 为 Python 规则配备了三条执行保障:

1. 编辑即检查的 Hook。 配置文件 .kiro/hooks/python-lint-on-edit.kiro.hook 定义了:当 *.py 文件被编辑保存时(when.type = fileEdited),触发 Agent 对改动文件做"类型错误、PEP 8 违规、常见反模式"的即时检查并标记问题。这与 steering 文件的 fileMatch: "*.py" 在触发面上完全对齐——一个负责"写之前给规则",一个负责"写之后给检查"。

2. 专职评审 Agent。 仓库提供 python-reviewer agent(描述见 .kiro/README.md):专门按 PEP 8、类型注解、错误处理与最佳实践评审 Python 代码。规则文件负责把"应然"注入上下文,评审 Agent 负责把"实然"与规则对照。

3. 可落地的工具链配置。 ECC 仓库自身的 pyproject.toml 是这些模式可被执行工具验证的实证:ruff 开启 E/F/I/N/W/UP 规则集、mypy 设定 python_version 与严格检查、pytest 配置 testpathsasyncio_mode = "auto";同时 typing 相关依赖与 src/ 布局(见 [tool.hatch.build.targets.wheel] packages = ["src/llm"])正是 skill 中"标准项目布局 + 现代工具链"一节的现实投影。换到任何项目,都可以参照这套配置把"Protocol、dataclass、惰性迭代"等模式变成机器可判定的门槛。

七、把这份模式清单用进你自己的项目

若想让自己的 Kiro / Claude Code / Codex 项目获得同样的 Python 模式约束,可按 .kiro/README.md 的安装方式操作:

# 定位到 .kiro 组件目录(Kiro 版 ECC 组件集)
cd .kiro

# 安装到指定项目(非破坏性拷贝,不覆盖既有文件)
./install.sh /path/to/your/project

# 或安装到当前目录 / 全局(对所有 Kiro 项目生效)
./install.sh
./install.sh ~

安装后,steering、skills、hooks 三类组件即可协同工作:编辑 .py 时自动加载本规则文件;需要完整模式参考时在对话中输入 /python-patterns 唤起 skill;保存文件时由 python-lint-on-edit hook 触发即时自检。你也可以复制 rules/python/patterns.mdrules/python/coding-style.md 到自己的 ECC 规则目录,使规则随代码评审流程一起生效。

实践建议速查:新写 Python 模块前先问三个问题——接口依赖是否需要"鸭子但可静态校验"(用 Protocol);跨层传递的数据是否需要自描述(用 dataclass/frozen=True DTO);资源或大数据的生命周期是否已交给 with 与生成器。这三个问题覆盖了 .kiro/steering/python-patterns.md 的全部要点,也是 Python 代码保持"可读、显式、最少惊讶"的最低门槛——正如 python-patterns skill 收尾所强调的:when in doubt, prioritize clarity over cleverness。

登录后查看全文
热门项目推荐
相关项目推荐