类型注解与代码质量
本节定位
这一节把注意力从“代码能跑”推进到“代码好维护”。类型注解、格式化工具和代码检查工具能让你在项目变大、多人协作、调用复杂库时少犯错,也能让未来的自己更快读懂代码。
学习目标
- 理解为什么需要类型注解
- 掌握 Python 类型注解的基本语法
- 了解常用的代码质量工具(linter、formatter)
- 养成编写高质量代码的习惯
为什么需要类型注解?
Python 是动态类型语言——变量不需要声明类型。这让写代码很灵活,但也带来一个问题:
def calculate_total(items, tax):
return sum(items) * (1 + tax)
# 用的时候,你得猜:
# items 是什么?列表?元组?
# tax 是什么?0.1?还是 "10%"?
# 返回什么?数字?字符串?
当项目变大时,没有类型信息的代码就像没有路标的高速公路——你得靠猜。
类型注解的作用:
| 好处 | 说明 |
|---|---|
| 自文档化 | 一看就知道函数要什么参数、返回什么 |
| IDE 智能提示 | VS Code 能给出更准确的自动补全 |
| 静态检查 | 在运行前就发现类型错误 |
| 团队协作 | 降低沟通成本,代码自己说话 |
基本类型注解
变量注解
# 基本类型
name: str = "小明"
age: int = 25
height: float = 1.75
is_student: bool = True
# Python 不会强制检查类型注解
# 以下代码不会报错,但静态检查工具会警告
age: int = "二十五" # 类型注解说是 int,实际赋了 str
类型注解只是"建议"
Python 的类型注解不会在运行时强制执行。即使类型不匹配,程序也能运行。它主要是给开发者和工具看的。真正的类型检查需要用 mypy 等静态检查工具。
函数注解
def greet(name: str) -> str:
"""
name: str → 参数 name 的类型是 str
-> str → 返回值的类型是 str
"""
return f"你好,{name}!"
def calculate_bmi(weight: float, height: float) -> float:
"""计算 BMI"""
return weight / (height ** 2)
def train_model(epochs: int = 10, lr: float = 0.001) -> None:
"""返回 None 的函数"""
print(f"训练 {epochs} 轮,学习率 {lr}")
有了类型注解,VS Code 的智能提示会变得非常准确——当你输入 greet( 时,它会提示你参数类型是 str。
复合类型注解
列表和字典
# Python 3.9+:直接用内置类型
scores: list[int] = [85, 92, 78]
student: dict[str, int] = {"张三": 85, "李四": 92}
coordinates: tuple[float, float] = (3.14, 2.71)
unique_ids: set[int] = {1, 2, 3}
# Python 3.8 及更早:需要从 typing 导入
from typing import List, Dict, Tuple, Set
scores: List[int] = [85, 92, 78]
student: Dict[str, int] = {"张三": 85, "李四": 92}
Optional:可能为 None 的值
from typing import Optional
def find_student(name: str) -> Optional[dict]:
"""查找学生,找不到返回 None"""
students = {"张三": {"age": 20}, "李四": {"age": 21}}
return students.get(name)
# Python 3.10+ 可以用更简洁的写法
def find_student(name: str) -> dict | None:
...
Union:多种可能的类型
from typing import Union
def process(data: Union[str, list]) -> str:
"""接受字符串或列表"""
if isinstance(data, list):
return ", ".join(str(item) for item in data)
return data
# Python 3.10+ 的简洁写法
def process(data: str | list) -> str:
...
Callable:函数类型
from typing import Callable
def apply_func(func: Callable[[int, int], int], a: int, b: int) -> int:
"""接受一个函数作为参数"""
return func(a, b)
result = apply_func(lambda x, y: x + y, 3, 5) # 8
更多类型注解
from typing import Any, Literal
# Any:任意类型
def log(message: Any) -> None:
print(message)
# Literal:只接受特定的值
def set_mode(mode: Literal["train", "eval", "test"]) -> None:
print(f"模式: {mode}")
set_mode("train") # ✅
set_mode("play") # 静态检查会警告
类型注解实战
为函数添加类型注解
def analyze_scores(
scores: list[float],
subject: str = "未知",
pass_line: float = 60.0
) -> dict[str, float | int | str]:
"""分析成绩,返回统计信息"""
if not scores:
return {"error": "成绩列表为空"}
return {
"subject": subject,
"count": len(scores),
"average": sum(scores) / len(scores),
"max": max(scores),
"min": min(scores),
"pass_count": sum(1 for s in scores if s >= pass_line)
}
为类添加类型注解
class DataProcessor:
def __init__(self, name: str, data: list[dict[str, Any]]) -> None:
self.name: str = name
self.data: list[dict[str, Any]] = data
self._processed: bool = False
def filter_by(self, key: str, value: Any) -> list[dict[str, Any]]:
"""按条件过滤数据"""
return [item for item in self.data if item.get(key) == value]
def get_column(self, key: str) -> list[Any]:
"""提取某一列"""
return [item[key] for item in self.data if key in item]
代码质量工具
好的代码不仅要能运行,还要可读、规范、少 bug。以下工具帮你做到这一点。
代码格式化:black
black 是 Python 最流行的代码格式化工具, 它会自动帮你把代码格式化成统一风格。
# 安装
pip install black
# 格式化单个文件
black my_script.py
# 格式化整个目录
black src/
# 只检查不修改
black --check my_script.py
格式化前:
x = { 'a':37,'b':42,
'c':927}
y = 'hello ''world'
z = 'hello '+'world'
a = [1,2,3,4,5,]
格式化后:
x = {"a": 37, "b": 42, "c": 927}
y = "hello " "world"
z = "hello " + "world"
a = [1, 2, 3, 4, 5]
代码检查:ruff
ruff 是新一代的 Python linter,速度极快,能发现很多常见问题。
# 安装
pip install ruff
# 检查代码
ruff check my_script.py
# 自动修复
ruff check --fix my_script.py
# 格式化(ruff 也可以替代 black)
ruff format my_script.py
类型检查:mypy
# 安装
pip install mypy
# 检查类型
mypy my_script.py
# example.py
def add(a: int, b: int) -> int:
return a + b
result = add("hello", "world") # mypy 会报错:参数类型不对!
$ mypy example.py
example.py:4: error: Argument 1 to "add" has incompatible type "str"; expected "int"
VS Code 集成
在 VS Code 中安装以下扩展,可以实时看到代码质量问题:
| 扩展 | 功能 |
|---|---|
| Pylance | 类型检查和智能提示(VS Code 自带推荐) |
| Ruff | 实时代码检查 |
| Black Formatter | 保存时自动格式化 |
推荐在 VS Code 设置中添加:
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "charliermarsh.ruff",
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
}
}