Python 的 typing:先把类型写清楚,再让工具帮你查错
Python 的 typing:先把类型写清楚,再让工具帮你查错
写 Python 时最常见的运行时报错,十有八九是类型对不上:函数明明要一个数字,传进来一个字符串;明明返回一个列表,某个分支却返回了 None。代码跑起来之前什么都看不出来,等报错时往往已经是线上。typing 就是为这件事准备的:把“这个参数应该是什么类型”写在代码里,让检查工具在运行前就把错指出来。
先从最基础的注解写起。没有注解的函数,读的人只能靠猜:
def total(prices):
return sum(prices)
加上注解,意图立刻清楚:
def total(prices: list[float]) -> float:
return sum(prices)
list[float] 是说“一个由浮点数组成的列表”,-> float 是说“返回一个浮点数”。注解本身不改变运行结果——Python 运行时不会因为传错类型就拦截你,它只是把约定写在了明处。真正发挥作用的是检查工具:mypy 读到 total(["3", "5"]) 就会在运行前报错,而不是等 sum 在线上抛 TypeError。注解写给人看,也写给工具看,两件事是一件。
第二个顺手的是 Optional 和 Union,专治“有时有、有时没有”的返回值。查不到用户时返回 None,是很多函数都会有的分支:
from typing import Optional
def find_user(user_id: int) -> Optional[dict]:
...
Optional[dict] 的意思是“要么是一个字典,要么是 None”,调用方看到这个注解,就知道必须先判断返回值是不是 None 再用它,不会直接写 user["name"] 然后在线上撞上 NoneType 报错。同理,Union[int, str] 表示“整数或字符串二选一”,比含糊的“都行”精确得多。类型写得越具体,调用方踩坑的可能就越小;写不出来具体类型,往往说明这个函数的职责本身还不够清楚。
第三个要分清的是 TypedDict 和 dataclass 的分工。两者都能描述“带固定字段的一组数据”,但用途不同:
from typing import TypedDict
class UserInfo(TypedDict):
name: str
age: int
TypedDict 描述的是字典的形状——数据本来就是字典(比如接口返回的 JSON),只是想让它的字段名和字段类型有据可查,访问时还是 info["name"]。而 dataclass 描述的是一个真正的对象,字段访问用 user.name,还能自带方法和默认值。数据从外部进来、形状固定但只是“过一下手”,用 TypedDict;数据要在程序内部长期流转、参与业务逻辑,用 dataclass。分不清时先问一句:这份数据是字典,还是对象?
最后记住三点:注解不强制、不拦截,它只是约定,检查靠 mypy 这类工具在运行前完成;Optional 是在提醒调用方“可能没有,先判断再用”;TypedDict 管字典的形状,dataclass 管对象的行为。类型不是给代码加负担,是把“这里应该是什么”从脑子里的假设变成代码里的事实——写的时候多花一行,查错的时候少花半天。
- 点赞
- 收藏
- 关注作者
评论(0)