知识点思维导图
25 个知识节点
参考资料
Python(11) - 类型注解
读完后,你应能完成以下任务:
- 绘制“Python(11) - 类型注解 / 先给锚点:和 TS 的类型标注几乎一一对应”的关键对象与数据流,解释“唯一要适应的小差异:返回值用 ->(箭头),不是冒号。”,并用源码位置、日志或 Trace 标注证据。
- 为“Python(11) - 类型注解 / 边界一(最重要):注解默认不检查,写错也照样跑”设计正常与异常输入,验证“这是前端从 TS 过来必踩的第一个认知坑。”,输出首个偏差位置与回归测试结果。
- 实现“Python(11) - 类型注解 / 容器、可选、联合:写法对照”的最小代码或配置,检验“别写成 -> null,Python 里空值的类型名是 None(首字母大写)。”,输出命令、结果与 Diff,并说明不适用边界。
你在 TS 里享受过类型带来的红利:IDE 自动补全、改名安全、参数写错当场标红。Python 也有同款能力,叫 type hint(类型注解)。但它有一个让前端最容易误判的点——默认根本不检查、不报错、也不影响运行。本篇帮你把 TS 心智模型平移过来,并立刻划清那条最关键的边界:Python 的类型注解是"渐进的、给人和工具看的提示",不是 TS 那种会拦住你的强制约束。
一、先给锚点:和 TS 的类型标注几乎一一对应
TS 里你写 name: string,Python 写 name: str,位置、冒号、含义都一样:
// TS
function greet(name: string, age: number): string {
return `${name} is ${age}`
}
let count: number = 0 // 变量注解
const users: string[] = [] // 数组
对照表先建立直觉:
| TS | Python | 说明 |
|---|---|---|
name: string |
name: str |
参数 / 变量注解,位置一致 |
: number |
: int / : float |
Python 整数浮点分开 |
: boolean |
: bool |
布尔 |
): string { |
) -> str: |
返回值,TS 用 :,Python 用 -> |
string[] |
list[str] |
数组 / 列表 |
Record<string, number> |
dict[str, int] |
键值对 |
string | null |
str | None |
联合 / 可空 |
interface / type |
TypedDict / dataclass / Pydantic |
结构化类型(见后文) |
唯一要适应的小差异:返回值用 ->(箭头),不是冒号。其余的"在标识符后加冒号写类型"和 TS 一模一样。
二、边界一(最重要):注解默认不检查,写错也照样跑
这是前端从 TS 过来必踩的第一个认知坑。TS 的类型是编译期强约束——类型不对,tsc 直接编译失败、红线拦你。Python 的类型注解默认只是元数据:解释器读到它、存起来,但不验证、不报错、不影响运行。
// TS 对比:这行根本编译不过
function greet(name: string): string { return `hi ${name}` }
greet(123) // ❌ 编译错误:Argument of type 'number' ...
关键心智模型:Python 的注解 ≈ "写在代码里的注释 + 给工具看的提示"。真正帮你抓错的不是 Python 本身,而是外部工具(mypy / Pyright)和编辑器(VS Code 的 Pylance)。注解的价值在开发期(补全、跳转、静态检查),不在运行期。 类比:就像你只写了
.ts但从不跑tsc——类型写了,但没人帮你校验。Python 想要"校验",得额外装并主动跑 mypy。
这正是"渐进类型(gradual typing)"的含义:你可以只给关键函数加注解,其余不写也能跑,新老代码混着来。和 TS 的 // @ts-nocheck 文件能和严格文件共存是一个味道。
三、容器、可选、联合:写法对照
Python 3.9+ 起,容器类型可以直接用内置的小写 list/dict/tuple/set 来写泛型参数(老教程里的 from typing import List 已不必要):
可选 / 联合,对应 TS 的 | null 和 |:
// TS 对比
function findUser(uid: number): string | null { ... }
function log(msg: string, tag: string | null = null): void { ... }
小坑:
-> None对应 TS 的: void,表示"没有有意义的返回值"。别写成-> null,Python 里空值的类型名是None(首字母大写)。
如果你的运行环境还停留在 Python 3.8,list[int] / str | None 这种写法会报错,需要改用 from typing import List, Optional 的老写法。新项目用 3.10+ 即可无脑用新语法。
四、给函数和变量加注解的常见形态
// TS 对比:Callable 对应函数类型字面量
let onDone: (a: number, b: number) => number = add
let result: Record<string, number>
Callable[[int, int], int] 读法:第一个 [int, int] 是参数类型列表,第二个 int 是返回类型。这就是 TS 里 (a: number, b: number) => number 的 Python 写法。
五、结构化类型:从 interface 到 dataclass / TypedDict
TS 描述"对象长什么样"用 interface / type。Python 里有几种对应物,按场景选:
5.1 dataclass —— 最像 class 版的 interface
@dataclass 是标准库 dataclasses 提供的装饰器,自动根据注解生成 __init__ 等样板代码(装饰器机制见第 12 篇,这里先当"标签"用):
// TS 对比:interface 只描述形状,dataclass 还顺手给了构造函数
interface User {
name: string
age: number
isVip?: boolean
}
类比边界:TS 的
interface纯类型、运行期不存在;Python 的dataclass是真实的 class,运行期存在、能new(直接User(...))、能存数据。它更接近"自动帮你写好 constructor 的普通类"。
5.2 TypedDict —— 给"字典"标形状
如果数据天然是 dict(比如解析 JSON 拿到的),用 TypedDict 给它标键值结构,这个才最贴近 TS 的 interface:
选型口诀:要"带行为/带方法的对象" →
dataclass;只是"一坨带固定键的 JSON 字典" →TypedDict;这两个对应了 TS 里"用 class 还是用 interface 描述纯数据"的选择。
六、运行期真要校验?那是 Pydantic 的活
注解默认不校验(第二节),但 Web 开发里你真的需要"传进来的 JSON 字段类型不对就报错"。这件事 Python 标准库不做,由第三方库 Pydantic 来做——它是 FastAPI 的地基(FastAPI 见后续篇,此处先建立印象):
这正好补上第二节的"边界":
- 普通注解 / dataclass / TypedDict → 不做运行期校验(只给工具看)
- Pydantic
BaseModel→ 做运行期校验 + 类型转换 类比:Pydantic ≈ 前端的zod——把"类型声明"升级成"运行期真正会拦截脏数据的校验器"。FastAPI 接收请求体时就是靠它把 JSON 自动校验并转成对象。
七、让注解真正帮到你:跑起 mypy / Pylance
注解写了不等于有用,得让工具来读。两条路通常一起用:
- 编辑器实时提示:VS Code 装 Pylance(基于 Pyright),打开就有补全、跳转、类型红线,体验接近写 TS。这步零配置,最划算。
- 命令行静态检查:装
mypy,在 CI 或本地批量扫全项目。
pip install mypy # 安装静态类型检查器
mypy your_module.py # 扫描指定文件/目录,报出类型不匹配
类比:
mypy your_module.py≈ 前端跑tsc --noEmit——只做类型检查、不产出文件。区别在于 TS 几乎默认就跑,而 Python 的检查是你主动选择加上的一道关。不跑它,注解就只是好看的注释。
八、总结
- 先给锚点:和 TS 的类型标注几乎一一对应:唯一要适应的小差异:返回值用 ->(箭头),不是冒号。
- 边界一(最重要):注解默认不检查,写错也照样跑:这是前端从 TS 过来必踩的第一个认知坑。
- 容器、可选、联合:写法对照:别写成 -> null,Python 里空值的类型名是 None(首字母大写)。
- 给函数和变量加注解的常见形态:Callable[[int, int], int] 读法:第一个 [int, int] 是参数类型列表,第二个 int 是返回类型。
- 结构化类型:从 interface 到 dataclass / TypedDict:类比边界:TS 的 interface 纯类型、运行期不存在;
- 运行期真要校验?那是 Pydantic 的活:FastAPI 接收请求体时就是靠它把 JSON 自动校验并转成对象。
学完自测
选择所有正确答案;提交后逐项核对判断依据。