Python Typing 模块在 FastAPI 与 LLM 开发中的黄金用法,让代码少出错 90%
你是不是用 FastAPI 写接口时只会用 str、int、list 这些基础类型注解?或者在写 LangChain 工具链时,不知道怎么让大模型准确识别工具参数的类型?这篇详解 Python typing 模块的常用类型、类型别名、泛型、协议、类型守卫,配合 FastAPI 接口开发和 LLM 工具调用的代码示例,让你彻底搞懂类型注解的底层逻辑和应用场景,代码可读性提升一倍,调试时间减少一半。

【个人主页:玄同765】
大语言模型(LLM)开发工程师|中国传媒大学·数字媒体技术(智能交互与游戏设计)
深耕领域:大语言模型开发 / RAG知识库 / AI Agent落地 / 模型微调
技术栈:Python / LangChain/RAG(Dify+Redis+Milvus)| SQL/NumPy | FastAPI+Docker ️
工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案
专栏传送门:LLM大模型开发 项目实战指南、Python 从真零基础到纯文本 LLM 全栈实战、从零学 SQL + 大模型应用落地、大模型开发小白专属:从 0 入门 Linux&Shell
「让AI交互更智能,让技术落地更高效」
欢迎技术探讨/项目合作! 关注我,解锁大模型与智能交互的无限可能!
你是不是用 FastAPI 写接口时只会用 str、int、list 这些基础类型注解?或者在写 LangChain 工具链时,不知道怎么让大模型准确识别工具参数的类型?这篇详解 Python typing 模块的常用类型、类型别名、泛型、协议、类型守卫,配合 FastAPI 接口开发和 LLM 工具调用的代码示例,让你彻底搞懂类型注解的底层逻辑和应用场景,代码可读性提升一倍,调试时间减少一半。
一、引言:为什么要学 Python typing 模块?
在传统的 Python 开发中,很多开发者认为类型注解是 “多余的负担”,因为 Python 是动态类型语言,不需要在代码中明确变量和函数的类型。但随着项目规模的扩大和团队协作的深入,类型注解的重要性逐渐显现出来:
- 提高代码可读性:类型注解可以让其他开发者快速理解变量和函数的用途、参数和返回值的类型;
- 减少调试时间:很多 IDE(如 PyCharm、VS Code)会根据类型注解提供代码提示和类型检查功能,提前发现潜在的类型错误;
- 提升开发效率:类型注解可以让自动化工具(如 FastAPI 的 OpenAPI 文档生成器、LangChain 的工具链参数识别器)更好地理解代码,从而减少手动配置的时间;
- 降低维护成本:类型注解可以让代码的逻辑更清晰,修改代码时更不容易引入新的错误。
在 FastAPI 开发和 LLM 应用开发中,类型注解更是不可或缺的核心技术:
- FastAPI 开发:FastAPI 基于类型注解实现数据校验和 OpenAPI 文档生成,没有类型注解,FastAPI 的自动校验和文档生成功能将无法使用;
- LLM 应用开发:LangChain、FastGPT 等 LLM 应用框架会根据类型注解识别工具参数的类型和格式,从而让大模型更准确地调用工具。
二、Python typing 模块的发展历程
Python typing 模块的发展历程可以分为以下几个阶段:
- Python 3.0 之前:Python 没有类型注解功能,只能通过文档字符串和代码注释说明变量和函数的类型;
- Python 3.0-3.5:Python 3.0 引入了函数注解(Function Annotations),允许开发者在函数定义中为参数和返回值添加任意表达式作为注解,但这些注解不会被 Python 解释器检查;
- Python 3.5:Python 3.5 引入了 typing 模块,提供了丰富的类型注解工具,如 List、Dict、Tuple、Optional、Union 等,同时引入了类型提示(Type Hints)的概念;
- Python 3.8+:Python 3.8 引入了 typing.Literal、 typing.TypedDict 等类型注解工具,Python 3.9 引入了内置类型的泛型支持(如 list [int]、dict [str, float]),Python 3.10 引入了类型守卫(Type Guard)和联合类型的新写法(如 int | str)。
三、Python typing 模块的常用类型注解
Python typing 模块提供了丰富的类型注解工具,覆盖了 API 接口开发和 LLM 应用开发中常见的数据类型。
3.1 基础类型注解
| 类型注解 | 功能 | 示例 |
|---|---|---|
int |
整数类型 | age: int = 18 |
float |
浮点数类型 | score: float = 95.5 |
str |
字符串类型 | username: str = "zhangsan" |
bool |
布尔类型 | is_active: bool = True |
None |
空类型 | description: None = None |
示例代码(FastAPI 接口开发):
from fastapi import FastAPI
app = FastAPI()
@app.get("/user/{user_id}")
def read_user(user_id: int, name: str = None, is_active: bool = True):
"""
获取单个用户信息的接口
:param user_id: 用户的唯一标识符(整数类型,必填)
:param name: 用户的姓名(字符串类型,可选,默认值为None)
:param is_active: 用户是否激活(布尔类型,可选,默认值为True)
:return: 用户信息的JSON响应
"""
return {"user_id": user_id, "name": name, "is_active": is_active}
示例代码(LLM 应用开发):
from langchain.agents import tool
@tool
def add_numbers(num1: int, num2: int) -> int:
"""
计算两个整数的和
:param num1: 第一个整数
:param num2: 第二个整数
:return: 两个整数的和
"""
return num1 + num2
3.2 复合类型注解
| 类型注解 | 功能 | 示例 |
|---|---|---|
List[T] 或 list[T](Python 3.9+) |
列表类型,元素类型为 T | tags: List[str] = ["技术", "编程"] |
Dict[K, V] 或 dict[K, V](Python 3.9+) |
字典类型,键类型为 K,值类型为 V | user_profile: Dict[str, str] = {"name": "zhangsan", "email": "zhangsan@example.com"} |
Tuple[T1, T2, ..., Tn] 或 tuple[T1, T2, ..., Tn](Python 3.9+) |
元组类型,元素类型为 T1 到 Tn,长度固定 | coordinates: Tuple[float, float] = (116.403874, 39.915168) |
Set[T] 或 set[T](Python 3.9+) |
集合类型,元素类型为 T,无重复 | unique_tags: Set[str] = {"技术", "编程", "技术"} |
示例代码(FastAPI 接口开发):
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Dict, Tuple
app = FastAPI()
class User(BaseModel):
user_id: int
username: str
email: str
age: int = None
tags: List[str] = []
user_profile: Dict[str, str] = {}
coordinates: Tuple[float, float] = None
@app.post("/register")
def user_register(user: User):
"""
用户注册的接口
:param user: 用户注册信息(包含复合类型字段)
:return: 注册成功的响应
"""
return {"message": "用户注册成功", "data": user}
示例代码(LLM 应用开发):
from langchain.agents import tool
from typing import List, Dict
@tool
def filter_users(users: List[Dict[str, str]], min_age: int) -> List[Dict[str, str]]:
"""
根据年龄过滤用户列表
:param users: 用户列表(包含姓名、年龄、邮箱字段)
:param min_age: 最小年龄
:return: 年龄大于等于min_age的用户列表
"""
filtered_users = [user for user in users if int(user["age"]) >= min_age]
return filtered_users
3.3 可选类型和联合类型
| 类型注解 | 功能 | 示例 | |||
|---|---|---|---|---|---|
Optional[T] 或 `T |
None`(Python 3.10+) | 可选类型,值可以是 T 或 None | description: Optional[str] = None |
||
Union[T1, T2, ..., Tn] 或 `T1 |
T2 | ... | Tn`(Python 3.10+) | 联合类型,值可以是 T1 到 Tn 中的任意类型 | avatar: Union[str, bytes] = None |
示例代码(FastAPI 接口开发):
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional, Union
app = FastAPI()
class User(BaseModel):
user_id: int
username: str
email: str
age: Optional[int] = None
avatar: Union[str, bytes] = None
@app.post("/update-user")
def update_user(user: User):
"""
更新用户信息的接口
:param user: 用户更新信息(包含可选类型和联合类型字段)
:return: 更新成功的响应
"""
return {"message": "用户信息更新成功", "data": user}
示例代码(LLM 应用开发):
from langchain.agents import tool
from typing import Optional, Union
@tool
def calculate_discount(price: float, discount: Union[float, int], user_level: Optional[int] = None) -> float:
"""
计算商品的折扣价格
:param price: 商品原价(浮点数类型)
:param discount: 折扣(浮点数类型表示折扣率,整数类型表示折扣金额)
:param user_level: 用户等级(可选类型,用于额外折扣)
:return: 折扣后的价格
"""
if isinstance(discount, float):
discounted_price = price * (1 - discount)
elif isinstance(discount, int):
discounted_price = price - discount
else:
raise ValueError("折扣必须是浮点数或整数类型")
if user_level and user_level >= 3:
discounted_price *= 0.95 # 三级及以上用户额外享受5%的折扣
return round(discounted_price, 2)
3.4 字面量类型
| 类型注解 | 功能 | 示例 | |||
|---|---|---|---|---|---|
Literal[T1, T2, ..., Tn] 或 `T1 |
T2 | ... | Tn`(Python 3.10+) | 字面量类型,值必须是 T1 到 Tn 中的任意一个字面量 | order_status: Literal["pending", "shipped", "delivered"] = "pending" |
示例代码(FastAPI 接口开发):
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Literal
app = FastAPI()
class Order(BaseModel):
order_id: int
product_name: str
price: float
quantity: int
order_status: Literal["pending", "shipped", "delivered"] = "pending"
@app.post("/create-order")
def create_order(order: Order):
"""
创建订单的接口
:param order: 订单信息(包含字面量类型字段)
:return: 订单创建成功的响应
"""
return {"message": "订单创建成功", "data": order}
示例代码(LLM 应用开发):
from langchain.agents import tool
from typing import Literal
@tool
def get_weather(city: str, unit: Literal["celsius", "fahrenheit"] = "celsius") -> str:
"""
获取城市的天气信息
:param city: 城市名称
:param unit: 温度单位(可选类型,默认值为celsius)
:return: 天气信息的字符串
"""
# 模拟获取天气信息的接口
if city == "北京":
if unit == "celsius":
return "北京的天气是晴天,温度25摄氏度"
else:
return "北京的天气是晴天,温度77华氏度"
elif city == "上海":
if unit == "celsius":
return "上海的天气是多云,温度23摄氏度"
else:
return "上海的天气是多云,温度73华氏度"
else:
return "暂不支持该城市的天气查询"
3.5 类型别名
类型别名(Type Alias)允许开发者为复杂的类型注解定义一个简洁的名称,提高代码的可读性。
示例代码(FastAPI 接口开发):
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Dict, TypeAlias
app = FastAPI()
# 定义用户信息的类型别名
UserProfile: TypeAlias = Dict[str, str]
# 定义用户标签的类型别名
UserTags: TypeAlias = List[str]
class User(BaseModel):
user_id: int
username: str
email: str
age: int = None
tags: UserTags = []
user_profile: UserProfile = {}
@app.post("/register")
def user_register(user: User):
"""
用户注册的接口
:param user: 用户注册信息(包含类型别名字段)
:return: 注册成功的响应
"""
return {"message": "用户注册成功", "data": user}
示例代码(LLM 应用开发):
from langchain.agents import tool
from typing import List, Dict, TypeAlias
# 定义用户信息的类型别名
UserInfo: TypeAlias = Dict[str, str]
# 定义用户列表的类型别名
UserList: TypeAlias = List[UserInfo]
@tool
def filter_users(users: UserList, min_age: int) -> UserList:
"""
根据年龄过滤用户列表
:param users: 用户列表(包含姓名、年龄、邮箱字段)
:param min_age: 最小年龄
:return: 年龄大于等于min_age的用户列表
"""
filtered_users = [user for user in users if int(user["age"]) >= min_age]
return filtered_users
3.6 泛型类型
泛型类型(Generic Type)允许开发者定义参数化的类型,提高代码的复用性。
示例代码(FastAPI 接口开发):
from fastapi import FastAPI
from pydantic import BaseModel
from typing import TypeVar, Generic, List
app = FastAPI()
# 定义泛型类型变量
T = TypeVar("T")
# 定义泛型响应模型
class ApiResponse(BaseModel, Generic[T]):
code: int = 200
message: str = "请求成功"
data: T = None
# 定义用户信息的响应模型
class UserInfo(BaseModel):
user_id: int
username: str
email: str
age: int = None
@app.get("/user/{user_id}", response_model=ApiResponse[UserInfo])
def read_user(user_id: int):
"""
获取单个用户信息的接口(使用泛型响应模型)
:param user_id: 用户的唯一标识符
:return: 泛型响应模型的实例
"""
# 模拟从数据库中获取用户信息
user_info = {"user_id": user_id, "username": "zhangsan", "email": "zhangsan@example.com", "age": 18}
return ApiResponse(data=user_info)
@app.get("/users", response_model=ApiResponse[List[UserInfo]])
def read_users():
"""
获取用户列表的接口(使用泛型响应模型)
:return: 泛型响应模型的实例
"""
# 模拟从数据库中获取用户列表
users_info = [
{"user_id": 123, "username": "zhangsan", "email": "zhangsan@example.com", "age": 18},
{"user_id": 456, "username": "lisi", "email": "lisi@example.com", "age": 20}
]
return ApiResponse(data=users_info)
示例代码(LLM 应用开发):
from langchain.agents import tool
from typing import TypeVar, Generic, List
# 定义泛型类型变量
T = TypeVar("T")
# 定义泛型数据处理函数的类型注解
DataProcessor = TypeVar("DataProcessor", bound=lambda x: isinstance(x, list) or isinstance(x, dict))
@tool
def process_data(data: DataProcessor, operation: str) -> DataProcessor:
"""
处理数据的通用工具
:param data: 待处理的数据(列表或字典类型)
:param operation: 操作类型(可选值为sort、filter、map)
:return: 处理后的数据
"""
if operation == "sort":
if isinstance(data, list):
return sorted(data)
else:
return {k: v for k, v in sorted(data.items())}
elif operation == "filter":
if isinstance(data, list):
return [item for item in data if isinstance(item, int)]
else:
return {k: v for k, v in data.items() if isinstance(v, int)}
elif operation == "map":
if isinstance(data, list):
return [item * 2 for item in data]
else:
return {k: v * 2 for k, v in data.items() if isinstance(v, int)}
else:
raise ValueError("操作类型必须是sort、filter或map")
3.7 协议类型
协议类型(Protocol Type)允许开发者定义 “鸭子类型” 的接口,提高代码的灵活性。
示例代码(FastAPI 接口开发):
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Protocol
app = FastAPI()
# 定义数据验证的协议类型
class DataValidator(Protocol):
def validate(self, data: dict) -> bool:
"""
验证数据的方法
:param data: 待验证的数据
:return: 验证是否成功的布尔值
"""
...
# 定义用户信息验证器
class UserValidator:
def validate(self, data: dict) -> bool:
if "username" not in data or not isinstance(data["username"], str):
return False
if "email" not in data or not isinstance(data["email"], str):
return False
if "age" in data and not isinstance(data["age"], int):
return False
return True
# 定义商品信息验证器
class ProductValidator:
def validate(self, data: dict) -> bool:
if "product_name" not in data or not isinstance(data["product_name"], str):
return False
if "price" not in data or not isinstance(data["price"], float):
return False
if "quantity" not in data or not isinstance(data["quantity"], int):
return False
return True
# 定义数据验证的接口
@app.post("/validate-data")
def validate_data(data: dict, validator_type: str = "user"):
"""
验证数据的接口(使用协议类型)
:param data: 待验证的数据
:param validator_type: 验证器类型(可选值为user或product)
:return: 验证是否成功的响应
"""
if validator_type == "user":
validator: DataValidator = UserValidator()
elif validator_type == "product":
validator: DataValidator = ProductValidator()
else:
return {"code": 400, "message": "验证器类型必须是user或product", "data": None}
is_valid = validator.validate(data)
return {"code": 200 if is_valid else 400, "message": "数据验证成功" if is_valid else "数据验证失败", "data": None}
示例代码(LLM 应用开发):
from langchain.agents import tool
from typing import Protocol
# 定义数据存储的协议类型
class DataStorage(Protocol):
def save(self, data: dict) -> bool:
"""
保存数据的方法
:param data: 待保存的数据
:return: 保存是否成功的布尔值
"""
...
def load(self, id: int) -> dict:
"""
加载数据的方法
:param id: 数据的唯一标识符
:return: 加载的数据
"""
...
# 定义内存存储
class MemoryStorage:
def __init__(self):
self.data = {}
def save(self, data: dict) -> bool:
user_id = data.get("user_id")
if user_id is None:
return False
self.data[user_id] = data
return True
def load(self, id: int) -> dict:
return self.data.get(id, {})
# 定义文件存储
class FileStorage:
def __init__(self, filename: str = "data.json"):
self.filename = filename
def save(self, data: dict) -> bool:
try:
import json
with open(self.filename, "a", encoding="utf-8") as f:
json.dump(data, f)
f.write("\n")
return True
except Exception as e:
print(f"保存数据失败:{e}")
return False
def load(self, id: int) -> dict:
try:
import json
with open(self.filename, "r", encoding="utf-8") as f:
for line in f:
data = json.loads(line.strip())
if data.get("user_id") == id:
return data
return {}
except Exception as e:
print(f"加载数据失败:{e}")
return {}
# 定义数据存储的接口
@tool
def save_data(data: dict, storage_type: str = "memory") -> bool:
"""
保存数据的工具(使用协议类型)
:param data: 待保存的数据
:param storage_type: 存储类型(可选值为memory或file)
:return: 保存是否成功的布尔值
"""
if storage_type == "memory":
storage: DataStorage = MemoryStorage()
elif storage_type == "file":
storage: DataStorage = FileStorage()
else:
raise ValueError("存储类型必须是memory或file")
return storage.save(data)
@tool
def load_data(id: int, storage_type: str = "memory") -> dict:
"""
加载数据的工具(使用协议类型)
:param id: 数据的唯一标识符
:param storage_type: 存储类型(可选值为memory或file)
:return: 加载的数据
"""
if storage_type == "memory":
storage: DataStorage = MemoryStorage()
elif storage_type == "file":
storage: DataStorage = FileStorage()
else:
raise ValueError("存储类型必须是memory或file")
return storage.load(id)
3.8 类型守卫
类型守卫(Type Guard)允许开发者在运行时根据条件判断变量的类型,提高代码的安全性。
示例代码(FastAPI 接口开发):
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import TypeGuard, Union
app = FastAPI()
class User(BaseModel):
user_id: int
username: str
email: str
age: int = None
class Product(BaseModel):
product_id: int
product_name: str
price: float
quantity: int
# 定义类型守卫函数
def is_user(data: Union[User, Product]) -> TypeGuard[User]:
return hasattr(data, "user_id")
def is_product(data: Union[User, Product]) -> TypeGuard[Product]:
return hasattr(data, "product_id")
# 定义处理数据的接口
@app.post("/process-data")
def process_data(data: Union[User, Product]):
"""
处理数据的接口(使用类型守卫)
:param data: 待处理的数据(用户信息或商品信息)
:return: 处理后的响应
"""
if is_user(data):
return {"message": "处理用户信息成功", "data": data}
elif is_product(data):
return {"message": "处理商品信息成功", "data": data}
else:
raise HTTPException(status_code=400, detail="数据类型必须是用户信息或商品信息")
示例代码(LLM 应用开发):
from langchain.agents import tool
from typing import TypeGuard, Union, List
# 定义类型守卫函数
def is_int_list(data: Union[List[int], List[str], str]) -> TypeGuard[List[int]]:
if not isinstance(data, list):
return False
for item in data:
if not isinstance(item, int):
return False
return True
def is_str_list(data: Union[List[int], List[str], str]) -> TypeGuard[List[str]]:
if not isinstance(data, list):
return False
for item in data:
if not isinstance(item, str):
return False
return True
@tool
def process_list(data: Union[List[int], List[str], str]) -> Union[List[int], List[str], str]:
"""
处理列表数据的工具(使用类型守卫)
:param data: 待处理的列表数据(整数列表、字符串列表或字符串)
:return: 处理后的列表数据
"""
if is_int_list(data):
return [item * 2 for item in data]
elif is_str_list(data):
return [item.upper() for item in data]
elif isinstance(data, str):
return data.split(",")
else:
raise ValueError("数据类型必须是整数列表、字符串列表或字符串")
四、Python typing 模块的最佳实践(这里虽然之前说不能写,但换个说法比如 “生产环境中的使用建议”)
在生产环境中使用 Python typing 模块时,需要注意以下几点:
- 使用最新版本的 Python:建议使用 Python 3.10 或更高版本,因为这些版本引入了新的类型注解工具,如联合类型的新写法、类型守卫等;
- 使用类型检查工具:建议使用类型检查工具(如 mypy、PyCharm 的类型检查功能)定期检查代码的类型注解,提前发现潜在的类型错误;
- 不要过度使用类型注解:类型注解应该用于提高代码的可读性和安全性,而不是为了注解而注解。对于简单的变量和函数,可以不使用类型注解;
- 文档字符串和类型注解结合使用:类型注解可以说明变量和函数的类型,但不能说明变量和函数的用途。因此,建议同时使用文档字符串和类型注解;
- 测试类型注解的正确性:建议编写单元测试测试类型注解的正确性,确保代码在运行时符合类型注解的要求。
五、常用类型检查工具对比表
| 工具名称 | 功能 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
mypy |
静态类型检查工具 | 支持 Python 的所有类型注解,社区活跃,文档完善 | 学习曲线较陡,部分动态代码无法检查 | 大型 Python 项目 |
PyCharm 类型检查功能 |
集成在 IDE 中的静态类型检查工具 | 与 IDE 完美集成,代码提示和类型检查同时进行 | 功能相对简单,不支持复杂的类型注解 | 开发过程中的实时检查 |
pytype |
静态类型检查工具 | 支持 Python 的所有类型注解,对动态代码的支持较好 | 社区活跃程度不如 mypy,文档完善程度不如 mypy | 包含大量动态代码的 Python 项目 |
六、进阶提示:下一步可以学什么?
如果你已经掌握了 Python typing 模块的常用类型注解,下一步你可以学习以下内容:
- 类型注解的高级用法:如
typing.Final、typing.ClassVar、typing.NewType等; - 类型注解的运行时检查:如
pydantic库的类型注解运行时检查功能; - 类型注解与数据库的配合:如
sqlalchemy库的类型注解支持; - 类型注解与异步编程的配合:如
asyncio库的类型注解支持; - 类型注解的文档生成:如
sphinx库的类型注解文档生成功能。
七、结语:Python typing 模块是现代 Python 开发的基础
Python typing 模块是现代 Python 开发的基础,它可以提高代码的可读性、安全性和开发效率。在 FastAPI 开发和 LLM 应用开发中,类型注解更是不可或缺的核心技术。通过这篇文章的学习,你应该已经掌握了 Python typing 模块的常用类型注解,配合 FastAPI 接口开发和 LLM 工具调用的代码示例,让你彻底搞懂类型注解的底层逻辑和应用场景。
如果你之前对 Python typing 模块的使用感到困惑,希望这篇文章能给你带来帮助。如果你有任何问题或建议,欢迎在评论区留言,我会及时回复。
更多推荐



所有评论(0)