Files
DailyChallenge_ProgrammingD…/Day_3/README.md
T

92 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Day_3 · 函数与异常:后端程序的"骨架"和"安全网"
> 后端代码里出现频率最高的两个技巧:**把函数当参数传来传去**(日志、中间件的底层)
> 和 **异常处理**(参数校验、错误响应的底层)。
> 今天两道题都只用到基础语法,做完你就掌握了后端开发的两块地基。
## 今日知识点 → 以后在 Django / Celery 里对应什么
| 今天练的 | 以后在 Django/Celery 里会看到 |
| --- | --- |
| 函数作为参数、`*args`/`**kwargs` | 视图函数 `def index(request, **kwargs)`、中间件、Celery 任务 |
| 自定义异常 + try/except | `Http404`、`ValidationError`、Celery 任务失败与重试 |
---
## 题目一(必做):万能日志记录器(函数 + *args/**kwargs)
**背景**:后端程序要记录"哪个函数被调用了、用了多久",这叫**日志(logging)**。
Django 中间件、Celery 任务、接口调用统计里,到处都是这种"给函数包一层"的操作。
**要求**:写函数 `log_call(func)`,它接收一个**函数**作为参数,返回一个**新函数**。
新函数在被调用时:
1. 打印 `[LOG] 调用函数 <函数名>,参数为 args=(...), kwargs={...}`
2. 调用原函数,拿到结果
3. 打印 `[LOG] <函数名> 执行完成,耗时 x.xxxx 秒`(用 `time.time()` 算耗时)
4. 返回原函数的结果
参数要用 `*args` 和 `**kwargs` 打包——因为你不知道原函数会接收什么参数。
**示例**
```python
import time
def add(a, b):
return a + b
logged_add = log_call(add)
print(logged_add(1, 2))
# [LOG] 调用函数 add,参数为 args=(1, 2), kwargs={}
# [LOG] add 执行完成,耗时 0.0001 秒
# 3
```
**进阶(加分)**:给 `log_call` 加第二个参数 `label`(默认空字符串),
打印日志时带上标签,如 `log_call(add, label="核心计算")` → `[核心计算][LOG] ...`。
> 提示:如果你已经看过装饰器语法,可以用 `@log_call` 直接写在函数头上;
> 没学过就写成 `log_call(add)(1, 2)` 这种普通调用,两种都行。
**出题意图**:Django 视图函数接收 `request`、URL 参数通过 `**kwargs` 传进来;
Celery 的任务、日志中间件全部建立在"函数作为参数 + `*args/**kwargs`"之上。
---
## 题目二(必做):模拟注册接口的参数校验
**背景**:后端接口收到请求后的第一件事永远是**校验参数**。
字段缺失、格式不对,都要返回明确的错误信息,绝不能带着脏数据往下走。
Django 里抛 `ValidationError`、Celery 里任务失败后重试——这一切的起点都是 try/except。
**要求**:
1. 定义一个字典模拟前端传来的注册数据:
`data = {"username": "zhangsan", "email": "zs@163.com", "age": "20"}`(注意 age 是字符串)
2. 自定义一个异常类 `ValidationError(Exception)`。
3. 写函数 `validate_registration(data)`,按以下规则校验,**任何一个不满足就抛 `ValidationError`**:
- `username` 必须存在且长度 ≥ 3
- `email` 必须存在且同时包含 `@` 和 `.`
- `age` 必须存在、能转成 int、且 `1 <= age <= 120`
4. 在调用方用 try/except 捕获:失败打印 `校验失败: <异常信息>`,成功打印 `注册成功,欢迎 <username>!`
**进阶(加分)**:把规则本身做成数据——写一个通用函数
`validate(data, rules)`,其中 `rules` 是一个字典:
`{字段名: (校验函数, 错误信息)}`,返回所有不满足的字段的错误列表。
(提示:校验函数就是你平时写的普通函数或 lambda。)
这是后端参数校验框架(比如 DRF 的 Serializer)的雏形,能想出来说明你已经开始有"抽象"的意识了。
**出题意图**:Django forms / serializers 的校验、Celery 任务的失败处理,
核心模式都是"**校验 → 抛异常 → 上层捕获处理**"。
今天的题目就是把这个模式焊死在你的肌肉记忆里。
---
## 完成标准
- [ ] 题目一能打印出完整的调用日志(含进阶则 +1)
- [ ] 题目二能对"缺字段 / 格式错 / 年龄越界"三种情况分别报错(含进阶则 +1)
完成后打开 `参考解答.py` 对照。建议看完后关掉文件,自己再默写一遍。