痛点:写"数据类"重复劳动

# 没有 dataclass:手写
class User:
    def __init__(self, name, age, email):
        self.name = name
        self.age = age
        self.email = email

    def __repr__(self):
        return f"User(name={self.name!r}, age={self.age}, email={self.email!r})"

    def __eq__(self, other):
        return (self.name, self.age, self.email) == (other.name, other.age, other.email)

dataclass:一行装饰器搞定

from dataclasses import dataclass

@dataclass
class User:
    name: str
    age: int
    email: str


u = User("WadeLy", 30, "hi@x.com")
print(u)          # User(name='WadeLy', age=30, email='hi@x.com')
u == User("WadeLy", 30, "hi@x.com")   # True

@dataclass 自动生成 __init____repr____eq__——你只写字段。

默认值 / field()

from dataclasses import dataclass, field

@dataclass
class User:
    name: str
    age: int = 18                       # 简单默认值
    skills: list[str] = field(default_factory=list)   # 可变默认值要 factory
    created_at: str = field(default_factory=lambda: "now")

⚠️ 可变默认值(list / dict)必须用 field(default_factory=...)——不然所有实例共享一份!

冻结的 dataclass:不可变

@dataclass(frozen=True)
class Point:
    x: int
    y: int

p = Point(1, 2)
p.x = 10        # FrozenInstanceError

冻结后还能放进 set / 当 dict key(frozen 自动加 __hash__)。

TypedDict:dict 的"形状"

适合从 JSON / API 来的字典:

from typing import TypedDict

class User(TypedDict):
    name: str
    age: int

def show(u: User) -> None:
    print(u["name"])

show({"name": "WadeLy", "age": 30})        # OK,是 dict

它本质还是 dict——只是给 mypy 看的形状声明。运行时和普通 dict 一样。

NamedTuple:不可变的、长得像类的元组

from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int

p = Point(3, 4)
print(p.x, p.y)        # 3 4
print(p[0], p[1])      # 3 4    也能像元组用

NamedTuple 是元组,不可变 + 可哈希

三个对比

特性 dataclass TypedDict NamedTuple
底层类型 自定义类 dict tuple
可变 ✓(默认)
可哈希 frozen=True 才行 ✗(dict 不可哈希)
像元组拆包 ✓(x, y = p
放进 JSON 要 asdict ✓(已经是 dict) 可以 _asdict()
性能 高(就是 dict) 高(就是 tuple)

怎么选

  • 业务对象,可变:dataclass
  • JSON 形状声明:TypedDict
  • 坐标 / 区间这种小数据 + 不可变:NamedTuple
  • 配置 / 不可变值对象@dataclass(frozen=True)

dataclass 进阶:和 mypy 配合

from dataclasses import dataclass

@dataclass
class Order:
    items: list[str]
    total: float

    def add(self, item: str, price: float) -> None:
        self.items.append(item)
        self.total += price


# mypy 知道 items 是 list[str],total 是 float
# 写错时立刻报警

attrs / Pydantic:功能更强的替代

  • attrs:dataclass 的"祖宗",功能更多(验证、转换器)
  • Pydantic:FastAPI 标配。dataclass + 数据验证 + JSON 序列化一体。AI 项目几乎必用。
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

u = User.model_validate_json('{"name": "WadeLy", "age": 30}')   # 带验证!

下一篇讲异常体系与自定义异常