结业测验(10/7,闭卷)¶
第一、二部分 60 分钟笔答(20 题,每题 1 分);第三部分 30 分钟限时编码(10 分)。总分 30,≥24 通过。答案与参考实现见
exercises/solutions/final/。规则:不开 AI;第三部分可以开 REPL 与 pytest,但不能翻本仓库的答案目录。
第一部分:概念与预测(12 题)¶
- 生成器与列表推导式在"内存"与"可重复遍历"上各有什么区别?写出一行代码证明生成器只能遍历一次。
- 闭包"晚绑定"是什么?
[lambda: i for i in range(3)]的三个函数都返回什么?两种修法。 @functools.wraps保住了哪些属性?没有它,inspect.signature拿到的会是谁的签名?__eq__与__hash__的关系;@dataclass(frozen=True)为什么天然可哈希?Protocol与ABC各一句话;learn-agent里工具接口更适合哪一个,为什么?try/except/else/finally四段各在什么时候执行?finally里return会发生什么(3.14 会给你什么警告)?raise NewError(...) from e与不写from e的区别体现在哪里?什么时候用from None?- Pydantic:
Optional[int]、int | None = None、Field(default_factory=list)三者在"必填/可省略/默认值共享"上的区别。 model_dump()与model_dump(mode="json")的区别;model_json_schema()里required是怎么决定的?- 一段
async def端点里调用了time.sleep(1),5 个并发请求总耗时约多少?三种修法。 asyncio.gather与asyncio.TaskGroup在"一个任务失败"时的行为差异;ExceptionGroup怎么拆。httpx.Client应该建几次?不设超时的后果?哪些请求可以自动重试、哪些不可以?
第二部分:工程判断(8 题)¶
- src 布局解决了什么问题?
python src/kb/cli.py为什么会ModuleNotFoundError? pyproject.toml里[project.dependencies]与[dependency-groups].dev的区别;uv.lock的作用。logging:库模块里该写什么、不该写什么;logger.error(e)与logger.exception(e)的差别。- 正则
re.match/re.search/re.fullmatch的区别;.*与.*?的区别;什么时候不该用正则。 - SQLite:为什么必须参数化查询?
with conn:做了什么?为什么建表语句要IF NOT EXISTS? - pytest:
patch为什么要"打到使用处"?fixture 的yield之后的代码何时执行?覆盖率 100% 能说明什么、不能说明什么? - 分层架构:
services/为什么不能 importfastapi?领域异常如何变成 HTTP 状态码?这样做对 agent 项目有什么直接好处? - 安全五条:列出你在
kb/aggregator审查中真正修掉的三处,以及一条你判断"不需要修"的理由。
第三部分:限时编码(30 分钟,10 分)¶
在一个新目录里实现模块 bookshelf.py 和测试 test_bookshelf.py,要求:
领域
- BookshelfError(Exception) 基类;子类 BookNotFoundError、DuplicateIsbnError
- @dataclass(frozen=True) Book(id: int | None, isbn: str, title: str, tags: tuple[str, ...], added_at: datetime)
输入校验(Pydantic)
- BookIn:isbn 必须是 13 位数字(pattern=r"^\d{13}$");title 去首尾空白后 1–200 字;tags 默认空、最多 5 个、自动小写去重;未知字段拒绝(extra="forbid")
仓储
- BookRepository(Protocol):add(book) -> Book(分配 id)、get(id) -> Book | None、find_by_isbn(isbn) -> Book | None、list() -> list[Book]
- 至少一个实现:InMemoryBookRepository(SqliteBookRepository 加分)
服务
- Bookshelf(repo):
- add(data: dict) -> Book:用 BookIn 校验(失败让 ValidationError 抛出),ISBN 已存在抛 DuplicateIsbnError,added_at 用 UTC 当前时间
- get(id) -> Book:不存在抛 BookNotFoundError
- by_tag(tag) -> list[Book]:不区分大小写
测试(≥3 个,pytest)
- 正常添加:id 为 1、标题被 strip、标签小写去重
- 非法输入:至少一种(ISBN 位数错 / 标题空 / 标签超 5 / 多余字段)抛 ValidationError
- 重复 ISBN 抛 DuplicateIsbnError;不存在的 id 抛 BookNotFoundError
评分(10 分):领域与异常 2|Pydantic 校验 3|Protocol + 实现 2|服务逻辑 1|测试 2。ruff check 有警告扣 1,无类型注解扣 1。