TypedDict和dataclass的优缺点对比
TypedDict和dataclass的优缺点对比
一、生活化比喻
-
TypedDict 像一本字典册子:
- 📖 每页有固定栏目(键)
- ✏️ 可以随时添加新便签纸(动态字段)
- 📄 适合记录临时信息
-
dataclass 像电子表格:
- 📊 有严格定义的列(属性)
- 🔒 可以锁定某些列(不可变性)
- ⚙️ 自带计算功能(方法)
二、最简对比表
TypedDict | dataclass | |
---|---|---|
样子 | 字典 {} | 类实例 () |
用途 | 临时数据收纳盒 | 正式数据档案表 |
修改 | 随时可改 | 部分禁止修改 |
检查 | 只查栏目类型 | 严格类型检查 |
三、超简单代码示例
1. TypedDict 示例 - 记录宠物信息
from typing import TypedDict
# 定义宠物信息模板
class PetInfo(TypedDict):
name: str # 必须填写
age: int # 必须填写
color: str # 必须填写
# 创建实例
my_cat: PetInfo = {
"name": "小白",
"age": 2,
"color": "白色"
}
# 添加额外信息(允许但不推荐)
my_cat["favorite_food"] = "鱼罐头" # ✅ 允许
2. dataclass 示例 - 管理学生档案
from dataclasses import dataclass
@dataclass
class Student:
name: str # 学生姓名
grade: int # 年级
score: float # 平均分
# 自定义方法:判断是否优秀
def is_excellent(self):
return self.score >= 90.0
# 创建实例
xiaoming = Student(name="小明", grade=3, score=95.5)
print(xiaoming.is_excellent()) # 输出:True
# xiaoming.grade = "四年级" # ❌ 会报错!
四、选择口诀
要灵活,用字典(TypedDict)
要严谨,用表格(dataclass)
常变化,用字典
固定式,用表格
加方法,用表格
简单存,用字典
五、何时用哪个?
-
选TypedDict:
- 📱 处理API返回的JSON数据
- ⚡ 快速测试临时数据结构
- 🛠️ 已有字典需要类型提示
-
选dataclass:
- 📚 定义系统核心数据模型
- 🔐 需要防止数据被篡改
- 🧮 要给数据添加计算功能
具体应用场景代码示例
场景1:网络请求响应处理(TypedDict)
from typing import TypedDict, NotRequired
# 定义API响应结构(包含可选字段)
class UserResponse(TypedDict):
id: int
name: str
email: str
age: NotRequired[int] # 可选字段
friends: list[int] # 嵌套结构
# 模拟API请求
def fetch_user_data() -> UserResponse:
"""获取用户数据(模拟网络请求)"""
return {
"id": 123,
"name": "张三",
"email": "zhangsan@example.com",
"friends": [456, 789],
# age 字段可以省略
}
# 使用示例
user_data = fetch_user_data()
print(f"用户 {user_data['name']} 的好友数量:{len(user_data['friends'])}")
# 验证必填字段
def validate_response(data: UserResponse):
"""验证必要字段是否存在"""
assert "id" in data, "缺少用户ID"
assert "name" in data, "缺少用户名"
场景2:用户管理系统(dataclass)
from dataclasses import dataclass
from typing import List
@dataclass(frozen=True) # 设为不可变
class User:
user_id: int
username: str
email: str
roles: List[str]
def is_admin(self) -> bool:
"""检查是否是管理员"""
return "admin" in self.roles
@property
def email_domain(self) -> str:
"""获取邮箱域名"""
return self.email.split("@")[-1]
# 创建用户实例
admin_user = User(
user_id=1,
username="sys_admin",
email="admin@company.com",
roles=["admin", "operator"]
)
# 尝试修改会报错(因为设置了frozen=True)
# admin_user.username = "hacker" # ❌ 报错:dataclasses.FrozenInstanceError
# 数据转换示例
def create_user_from_dict(data: dict) -> User:
"""从字典创建用户"""
return User(
user_id=data["id"],
username=data["name"],
email=data["email"],
roles=data.get("roles", ["user"])
)
混合使用场景:Web接口开发
from fastapi import FastAPI
from typing import TypedDict
from dataclasses import asdict
app = FastAPI()
# API响应使用TypedDict
class ApiResult(TypedDict):
success: bool
data: dict
error: str
# 业务逻辑使用dataclass
@dataclass
class UserProfile:
username: str
signup_days: int
def vip_level(self) -> int:
return min(self.signup_days // 30, 5)
@app.get("/profile/{username}")
def get_profile(username: str) -> ApiResult:
"""获取用户资料接口"""
# 模拟数据库查询
profile = UserProfile(
username=username,
signup_days=150
)
return {
"success": True,
"data": asdict(profile), # 转换dataclass为字典
"error": ""
}