From 0f5d56a26dbd02b47fb8283121889d84148fde37 Mon Sep 17 00:00:00 2001 From: lkjing2021345 <1908499668@qq.com> Date: Mon, 28 Sep 2026 22:54:53 +0800 Subject: [PATCH] add exam questions: written (10 MC + 3 short), q1 JSON log pipeline, q2 user manager, project-a data layer, project-b interface layer --- README.md | 8 +- project-a/README.md | 69 ++++++++++++++ project-b/README.md | 79 ++++++++++++++++ q1/README.md | 103 +++++++++++++++++++++ q2/README.md | 56 +++++++++++ written.md | 220 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 530 insertions(+), 5 deletions(-) create mode 100644 project-a/README.md create mode 100644 project-b/README.md create mode 100644 q1/README.md create mode 100644 q2/README.md create mode 100644 written.md diff --git a/README.md b/README.md index 456da5e..5395d6d 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,6 @@ | 中等题 | 简答题 / 编程题 | 基础应用 | | 难题 | 项目 | 综合工程能力 | -具体题目与分值以后续发布为准。 - ## 提交方式 本次考核默认你已经学会了如何进行 git 开发并熟练掌握了 git 开发规范,因此我们不通过群聊收文件,**你的仓库就是唯一答卷**。 @@ -32,7 +30,7 @@ - `README.md`:简要说明; - `written.md`:选择题 + 简答题答案; -- `q2-xxx/`、`q3-xxx/`:各编程小题独立目录; +- `q2/`、`q3/`:各编程小题独立目录; - `project/`:难题项目,内含 README,说明项目功能、依赖与运行方式。 ### 3. 提交要求 @@ -53,6 +51,6 @@ - 考核期间不会有人对你的代码给出修改意见,请独立完成; - 你的提交历史、分支结构与代码本身同等重要,均会纳入评分; -- 对题目有疑问请在**题库仓库**提 Issue(注意不要贴出你的解答代码),共性问题我们会不定期汇总置顶。 +- 对题目有疑问请在**题库仓库**提 Issue(注意不要贴出你的解答代码),共性问题我们会不定期汇总置顶。(注:截至时间前**5个小时**,即10月7日21点之后的 issue 不予回复) -> 温馨提示:想着借助AI走捷径的同学注意,我们有非常完善的AI鉴别机制,要是被发现你是用AI做的题目,将直接取消考试资格。 \ No newline at end of file +> 温馨提示:想着借助AI走捷径的同学注意,我们有非常完善的AI鉴别机制,题目本身难度不大,但是要是被发现你是纯粹让AI代做的题目,将直接取消考试资格。 \ No newline at end of file diff --git a/project-a/README.md b/project-a/README.md new file mode 100644 index 0000000..05775b8 --- /dev/null +++ b/project-a/README.md @@ -0,0 +1,69 @@ +# 工程题 A:文章管理系统(数据层) + +> **本题为扩展题内容,二选一完成即可。** 选做一道,不强制。 +> 请在功能分支上开发,完成后通过 Pull Request 合并回 main。 + +## 项目背景 + +实现一个文章管理系统的**数据层**:文章模型、附件管理、操作审计、并发安全。核心挑战:合理的模型设计、Django 信号驱动的审计日志、文件附件管理、并发安全的计数器。 + +## 功能需求 + +### 必须实现 + +1. **数据模型** + - `Article`:标题、正文、作者(外键 → 用户,`CASCADE`)、状态(`draft` / `published` / `archived`)、浏览量(默认 0)、`created_at` / `updated_at`(自动记录) + - `Attachment`:文件名、文件(`FileField`)、关联文章(外键 → `Article`,`CASCADE`,`related_name="attachments"`)、上传时间 + - `AuditLog`:操作类型(`create` / `update` / `publish` / `archive` / `delete`)、关联文章(外键 → `Article`,`SET_NULL`,`null=True`)、操作人(外键 → 用户,`SET_NULL`,`null=True`)、时间戳、变更摘要(`JSONField`) + - 合理设置 `__str__`、`Meta` 排序、`verbose_name` + +2. **附件管理** + - 登录用户可为自己的文章上传附件(`FileField`,存到 `MEDIA_ROOT/attachments/`) + - 文章详情页展示附件列表 + - 作者可删除自己的附件 + - `settings.py` 配置 `MEDIA_URL` / `MEDIA_ROOT`,开发服务器能访问静态文件 + +3. **操作审计(信号驱动)** + - 每次文章创建、状态变更、删除,自动写入 `AuditLog` + - **必须用 Django 信号**(`post_save` / `pre_delete`)实现,禁止在视图里手动 `AuditLog.objects.create` + - 变更摘要用 `JSONField` 记录变更前后字段差异,如 `{"status": {"old": "draft", "new": "published"}}` + - 文章详情页底部展示该文章的审计日志(按时间倒序) + +4. **并发安全浏览量** + - 文章详情页每次访问浏览量 +1 + - **必须用 `F("views") + 1` 原子更新** + - 写注释说明:为什么 `article.views += 1; article.save()` 在并发下会丢更新 + +### 加分项 + +1. **封面图缩略图**:上传时自动生成 200px 宽缩略图(用 `Pillow`,存到 `MEDIA_ROOT/thumbnails/`) +2. **文章统计视图**:`/stats/` 展示总文章数、总浏览量、各状态文章数、最近 10 条审计日志 +3. **软删除**:文章删除时不真删,设 `is_deleted=True`,审计日志保留;列表页过滤已删除文章 +4. **附件下载计数**:每次下载附件 +1(`F("downloads") + 1`),展示在附件列表 + +## 技术要求 + +- Python 3 + Django +- 必须包含: + - `README.md`:项目说明、功能列表、依赖安装、运行方式 + - `requirements.txt`(含 `Pillow`) + - 可运行的 `manage.py` +- 密码存储必须用 Django 内置哈希(`set_password`),禁止明文 +- 审计日志必须用信号实现,禁止在视图里手动 `create` +- 代码遵循 PEP 8 + +## 评分标准 + +| 维度 | 权重 | 说明 | +| --- | --- | --- | +| 必须功能完成度 | 40% | 模型 + 附件 + 信号审计 + 并发浏览量 | +| 代码质量 | 25% | 模型设计、信号设计、无冗余、有注释 | +| 加分项 | 20% | 实现了多少可选功能 | +| 工程规范 | 15% | git 提交历史、分支管理、PR 流程、README 完整性 | + +## 提交要求 + +- 项目代码放在本目录 `project-a/` 下 +- 在功能分支上开发,完成后通过 Pull Request 合并回 main +- 保持过程性提交,提交信息应说明改动内容 +- 截止前(10月7日 23:59)仓库状态为准 diff --git a/project-b/README.md b/project-b/README.md new file mode 100644 index 0000000..f7ceea6 --- /dev/null +++ b/project-b/README.md @@ -0,0 +1,79 @@ +# 工程题 B:内容管理系统(接口层) + +> **本题为扩展题内容,二选一完成即可。** 选做一道,不强制。 +> 请在功能分支上开发,完成后通过 Pull Request 合并回 main。 + +## 项目背景 + +实现一个内容管理系统的**接口层**:文章状态工作流、REST API、Django Admin 定制、认证与权限。核心挑战:多状态状态机、API 设计与认证、Admin 深度定制、权限校验。 + +## 功能需求 + +### 必须实现 + +1. **数据模型** + - `Article`:标题、正文、作者(外键 → 用户,`CASCADE`)、状态(`draft` / `in_review` / `published` / `archived`)、浏览量(默认 0)、`created_at` / `updated_at`(自动记录) + - 合理设置 `__str__`、`Meta` 排序、`verbose_name` + +2. **文章工作流(状态机)** + - 状态转换:`draft` → `in_review` → `published` → `archived` + - 只有作者本人能执行状态转换(非作者返回 403) + - 非法转换(如 `draft` → `published` 跳过审核、`archived` → `draft` 回退)返回 400 + - 文章列表页:支持按状态筛选 + 按作者筛选 + 按标题搜索(`icontains`)+ 分页(每页 10 条) + +3. **REST API** + - `GET /api/articles/`:返回文章列表(JSON),支持 `?status=` 和 `?page=` 参数 + - `GET /api/articles//`:返回单篇文章详情 + - `POST /api/articles//transition/`:执行状态转换,body 含 `{"to": "in_review"}` + - API 返回标准 JSON 格式:成功 `{"data": ..., "message": "..."}`,失败 `{"error": "..."}` + 对应 HTTP 状态码 + - API 端点需登录认证(session 或 token 均可),未认证返回 401 + - 权限:只有作者能调用 `transition`,非作者返回 403 + +4. **Django Admin 定制** + - `Article` 在 Admin 中可增删改查 + - 自定义 `list_display`(标题、作者、状态、浏览量、创建时间) + - 自定义 `list_filter`(状态、作者) + - 自定义 `search_fields`(标题) + - 自定义 `actions`:批量发布(`draft`/`in_review` → `published`)、批量归档 + - 只读权限:非作者用户访问 Admin 时只能看,不能改(用 `has_change_permission` 控制) + +5. **认证与权限** + - 用户注册(用户名 + 密码,`set_password` 哈希存储) + - 登录 / 登出(session) + - 未登录用户只能浏览已发布文章的 API + - 所有写操作(状态转换)必须校验登录 + 作者权限 + +### 加分项 + +1. **API 版本化**:`/api/v1/articles/` 和 `/api/v2/articles/`,v2 返回额外字段(如 `word_count`、`reading_time`) +2. **全文搜索**:`GET /api/articles/?q=keyword` 支持标题 + 正文搜索 +3. **操作限制**:同一用户每分钟最多 5 次状态转换(用内存计数或数据库计数均可,写清实现思路) +4. **WebSocket 实时通知**:文章状态变更时,通过 WebSocket 通知该作者的其他在线会话(用 `channels` 或轮询模拟均可,写清思路) +5. **API 文档**:用 `drf-spectacular` 或手写 OpenAPI spec,生成 `/api/docs/` 页面 + +## 技术要求 + +- Python 3 + Django(可用 DRF,也可纯 Django 视图 + JSON 响应) +- 必须包含: + - `README.md`:项目说明、功能列表、依赖安装、运行方式、API 端点文档 + - `requirements.txt` + - 可运行的 `manage.py` +- 密码存储必须用 Django 内置哈希,禁止明文 +- 所有写操作必须校验登录 + 权限 +- 代码遵循 PEP 8 + +## 评分标准 + +| 维度 | 权重 | 说明 | +| --- | --- | --- | +| 必须功能完成度 | 40% | 模型 + 工作流 + API + Admin + 认证 | +| 代码质量 | 25% | 状态机设计、API 结构、权限逻辑、无冗余、有注释 | +| 加分项 | 20% | 实现了多少可选功能 | +| 工程规范 | 15% | git 提交历史、分支管理、PR 流程、README 完整性 | + +## 提交要求 + +- 项目代码放在本目录 `project-b/` 下 +- 在功能分支上开发,完成后通过 Pull Request 合并回 main +- 保持过程性提交,提交信息应说明改动内容 +- 截止前(10月7日 23:59)仓库状态为准 diff --git a/q1/README.md b/q1/README.md new file mode 100644 index 0000000..00cb4d2 --- /dev/null +++ b/q1/README.md @@ -0,0 +1,103 @@ +# 编程题 1:JSON 日志管道 + +> **硬性要求:本题必须完成。** 未完成的编程题不进入部门筛选流程。 + +## 题目描述 + +生产环境的日志通常是 **JSON Lines** 格式(每行一个 JSON 对象),例如 `app.jsonl`: + +```jsonl +{"timestamp": "2026-10-01 10:23:45", "level": "INFO", "message": "用户登录成功", "user": "张三"} +{"timestamp": "2026-10-01 10:24:01", "level": "ERROR", "message": "数据库连接失败", "user": "李四"} +{"timestamp": "2026-10-01 10:25:12", "level": "INFO", "message": "用户登出", "user": "张三"} +{"timestamp": "2026-10-01 10:26:30", "level": "ERROR", "message": "超时", "user": "李四"} +{"timestamp": "2026-10-01 10:27:00", "level": "INFO", "message": "任务完成", "user": "王五"} +``` + +请写一个函数 `analyze_log(filepath)`,接收一个 `.jsonl` 文件路径,返回一个统计字典。 + +## 返回格式 + +```python +{ + "total": 5, # 成功解析的日志总条数 + "by_level": { # 按 level 统计条数 + "INFO": 3, + "ERROR": 2, + }, + "by_user": { # 按 user 统计条数 + "张三": 2, + "李四": 2, + "王五": 1, + }, + "last_error": "超时", # 最后一条 level 为 ERROR 的 message;无 ERROR 则为 None +} +``` + +## 示例 + +### 示例 1 + +输入文件 `app.jsonl`(内容如上): + +```python +result = analyze_log("app.jsonl") +print(result["total"]) # 5 +print(result["by_level"]) # {'INFO': 3, 'ERROR': 2} +print(result["by_user"]) # {'张三': 2, '李四': 2, '王五': 1} +print(result["last_error"]) # 超时 +``` + +### 示例 2:文件不存在 + +```python +result = analyze_log("not_exist.jsonl") +print(result) +# {'total': 0, 'by_level': {}, 'by_user': {}, 'last_error': None} +``` + +### 示例 3:空文件 + +```python +# 文件存在但内容为空 +result = analyze_log("empty.jsonl") +print(result) +# {'total': 0, 'by_level': {}, 'by_user': {}, 'last_error': None} +``` + +### 示例 4:含格式错误的行 + +文件内容: + +```jsonl +{"timestamp": "2026-10-01 10:23:45", "level": "INFO", "message": "ok", "user": "张三"} +这不是合法的 JSON +{"timestamp": "2026-10-01 10:24:01", "level": "ERROR", "message": "失败", "user": "李四"} +``` + +```python +result = analyze_log("bad.jsonl") +print(result["total"]) # 2(跳过格式错误行) +print(result["by_level"]) # {'INFO': 1, 'ERROR': 1} +print(result["last_error"]) # 失败 +``` + +## 约束与要求 + +- 语言:Python 3 +- 实现文件:`main.py`(本目录下) +- 函数签名:`def analyze_log(filepath: str) -> dict:` +- 文件操作必须指定 `encoding="utf-8"` +- 文件不存在时返回空结果字典,**不得抛异常** +- 某行 `json.loads` 失败时跳过该行,**不得中断整个解析** +- 空文件返回空结果字典 +- 每行 JSON 保证包含 `timestamp`、`level`、`message`、`user` 四个键(格式正确的行) +- 不得引入第三方库(标准库 `json`、`os` 可用) +- 如有测试脚本,放在 `test.py` 中(该项作为可选项,如果完成会视测试规范度和完成度有一定的加分) + +## 提交要求 + +- 将代码放在本目录 `q1/` 下 +- 必须包含 `main.py`,可执行或可被 import 后调用 +- 如有测试脚本,放在 `test.py` 中(该项作为可选项,如果完成会视测试规范度和完成度有一定的加分) +- 保持过程性提交,最终代码需能直接运行 diff --git a/q2/README.md b/q2/README.md new file mode 100644 index 0000000..29b782f --- /dev/null +++ b/q2/README.md @@ -0,0 +1,56 @@ +# 编程题 2:用户管理器 + +> **硬性要求:本题必须完成。** 未完成的编程题不进入部门筛选流程。 + +## 题目描述 + +实现一个用户管理类,管理用户数据的增删查改,并支持 JSON 文件持久化。 + +每个用户是一个字典,形如 `{"id": 1, "name": "张三", "age": 18}`。`id` 由管理器自动分配,从 1 开始递增。 + +## 功能要求 + +该类需支持以下功能(方法命名、参数设计由你决定,需符合 Python 命名规范): + +- 添加用户(传入姓名和年龄),自动分配 id,返回该用户字典 +- 按 id 查询用户,不存在返回 `None` +- 修改指定用户的年龄,成功返回 `True`,用户不存在返回 `False` +- 删除指定用户,成功返回 `True`,用户不存在返回 `False` +- 列出所有用户(按添加顺序) +- 将所有用户保存为 JSON 文件 +- 从 JSON 文件加载用户,覆盖当前数据 + +## 行为示例 + +``` +um = UserManager() +um.add_user("张三", 18) → {"id": 1, "name": "张三", "age": 18} +um.add_user("李四", 20) → {"id": 2, "name": "李四", "age": 20} +um.get_user(1) → {"id": 1, "name": "张三", "age": 18} +um.get_user(99) → None +um.update_age(1, 19) → True +um.remove_user(2) → True +um.remove_user(2) → False +um.list_users() → [{"id": 1, "name": "张三", "age": 19}] +um.save_to_json("users.json") +um2 = UserManager() +um2.load_from_json("users.json") +um2.list_users() → [{"id": 1, "name": "张三", "age": 19}] +``` + +## 约束与要求 + +- 语言:Python 3 +- 实现文件:`main.py`(本目录下) +- 保存/加载必须使用 `json.dump` / `json.load` +- 文件操作必须指定 `encoding="utf-8"`,`ensure_ascii=False` +- 从文件加载后,后续添加用户的 id 应接续已加载的最大 id +- 不得引入第三方库(标准库 `json`、`os` 可用) +- 如有测试脚本,放在 `test.py` 中(该项作为可选项,如果完成会视测试规范度和完成度有一定的加分) + +## 提交要求 + +- 将代码放在本目录 `q2/` 下 +- 必须包含 `main.py`,可执行或可被 import 后调用 +- 如有测试脚本,放在 `test.py` 中(该项作为可选项,如果完成会视测试规范度和完成度有一定的加分) +- 保持过程性提交,最终代码需能直接运行 diff --git a/written.md b/written.md new file mode 100644 index 0000000..0ee7b6d --- /dev/null +++ b/written.md @@ -0,0 +1,220 @@ +# 选择题 + 简答题 + +> 本文件包含所有选择题与简答题,请在你的仓库中于本文件作答。 +> **硬性要求:本文件所有题目均必须完成,未完成的题目不进入部门筛选流程。** + +## 一、选择题(每题 2 分,共 10 题,满分 20 分) + +> 说明:单选,将答案写在本节末尾的「答案」行中,格式如 `1. A 2. B 3. C ...`。 + +1. 依次执行以下代码,输出是什么? + + ```python + def f(x, lst=[]): + lst.append(x) + return lst + + a = f(1) + b = f(2) + print(b) + ``` + + - A. `[2]` + - B. `[1, 2]` + - C. `[1]` + - D. `TypeError: 'list' object is not callable` + +2. 依次执行以下代码,输出是什么? + + ```python + a = [1, 2, 3] + b = a + c = a.copy() + a.append(4) + print(b, c) + ``` + + - A. `[1, 2, 3, 4] [1, 2, 3, 4]` + - B. `[1, 2, 3, 4] [1, 2, 3]` + - C. `[1, 2, 3] [1, 2, 3, 4]` + - D. `[1, 2, 3] [1, 2, 3]` + +3. 依次执行以下代码,输出是什么? + + ```python + try: + x = 1 / 0 + except ZeroDivisionError: + print("A") + else: + print("B") + finally: + print("C") + ``` + + - A. 只输出 `C` + - B. 输出 `A` 和 `C` + - C. 输出 `B` 和 `C` + - D. 输出 `A`、`B` 和 `C` + +4. 依次执行以下代码,输出是什么? + + ```python + s = " hello " + print(len(s)) + print(len(s.strip())) + ``` + + - A. `7 7` + - B. `7 5` + - C. `5 5` + - D. `5 7` + +5. 以下代码的执行结果是? + + ```python + for i in range(5): + if i == 3: + break + else: + print("done") + print("end") + ``` + + - A. 输出 `done` 和 `end` + - B. 只输出 `end` + - C. 只输出 `done` + - D. 什么都不输出 + +6. 依次执行以下代码,输出是什么? + + ```python + class Animal: + def __init__(self, name): + self.name = name + + def speak(self): + print("...") + + class Dog(Animal): + def speak(self): + print(f"{self.name}: woof") + + d = Dog("Rex") + d.speak() + ``` + + - A. `...` + - B. `Rex: woof` + - C. 输出两行:`...` 和 `Rex: woof` + - D. `AttributeError: 'Dog' object has no attribute '__init__'` + +7. 以下代码中,`d` 的值是什么? + + ```python + d = {"a": 1, "b": 2} + d = {k: v for k, v in d.items() if v > 1} + print(d) + ``` + + - A. `{'a': 1, 'b': 2}` + - B. `{'b': 2}` + - C. `{1: 'a', 2: 'b'}` + - D. `SyntaxError: invalid syntax` + +8. 依次执行以下代码,输出是什么? + + ```python + import json + s = json.dumps({"name": "张三", "age": 18}) + print(type(s)) + ``` + + - A. `` + - B. `` + - C. `` + - D. `TypeError: dump() missing 1 required positional argument: 'fp'` + +9. 依次执行以下代码,输出是什么? + + ```python + def f(x): + return x + 1 + + f(5) + print(f(5)) + ``` + + - A. 输出两行:`None` 和 `6` + - B. 只输出 `6` + - C. 只输出 `None` + - D. 输出 `6` 两次 + +10. 以下代码中,`user.get("city")` 和 `user["city"]` 的区别是什么? + + ```python + user = {"name": "张三", "age": 18} + ``` + + - A. 没有区别,两者行为完全一致 + - B. `get()` 返回默认值 `None`,`[]` 抛出 `KeyError` + - C. `get()` 抛出 `KeyError`,`[]` 返回 `None` + - D. `get()` 只能用于字符串键,`[]` 可以用于任意键 + +### 答案 + +(在此填写,格式:`1. A 2. B 3. C 4. D 5. A 6. B 7. C 8. D 9. A 10. B`) + +--- + +## 二、简答题(每题 10 分,共 3 题,满分 30 分) + +> 说明:直接在本文件对应题目下方作答,支持代码块。 + +### 第 1 题:浅拷贝与深拷贝 + +以下代码中,`a`、`b`、`c` 三者之间的关系是什么?执行 `a[0].append(99)` 后,`b` 和 `c` 分别变成什么?请解释原因。 + +```python +a = [[1, 2], [3, 4]] +b = a.copy() +import copy +c = copy.deepcopy(a) +``` + +(在此作答) + +### 第 2 题:字典与列表的综合应用 + +以下代码模拟"从日志中提取用户信息",请回答: + +```python +logs = [ + {"user": "张三", "action": "login", "level": "INFO"}, + {"user": "李四", "action": "logout", "level": "INFO"}, + {"user": "张三", "action": "error", "level": "ERROR"}, + {"user": "王五", "action": "login", "level": "INFO"}, + {"user": "李四", "action": "error", "level": "ERROR"}, +] +``` + +1. 写出表达式,找出所有 `level` 为 `"ERROR"` 的日志(返回字典列表)。 +2. 写出表达式,统计每个用户出现了几次(返回字典,键为用户名,值为次数)。 +3. 解释为什么第 2 问不能直接用 `len(logs)` 得到结果,需要什么遍历结构? + +(在此作答) + +### 第 3 题:异常处理设计 + +Day_10 中你写过 `safe_int(s)` 函数:能转就返回整数,不能转就返回 `None`。 + +现在请你设计一个 `safe_divide(a, b)` 函数: + +- 输入两个字符串 `a` 和 `b` +- 尝试将它们转为数字并计算 `a / b` +- 如果转换失败(`ValueError`)或除数为零(`ZeroDivisionError`),返回 `None` +- 否则返回商(`float`) + +请写出函数代码,并说明:为什么这里用 `try/except` 比先用 `if` 判断再计算更好? + +(在此作答)