小白学 Python
AI 编程指南
© 2026 小白学 Python · 基于 walter201230/Python 教程
课程目录关于本站联系方式隐私政策GitHub

全部课程

  1. 00为什么学 Python
  2. 01Python 安装与第一个程序
  3. 02基本数据类型与变量
  4. 03List 与 Tuple
  5. 04Dict 与 Set
  6. 05条件与循环
  7. 06函数
  8. 07迭代
  9. 08面向对象
  10. 09模块
  11. 10魔法方法
  12. 11枚举类
  13. 12元类 metaclass
  14. 13线程与进程
  15. 14正则表达式
  16. 15闭包
  17. 16装饰器
  18. 17代码可读性
  19. 18pathlib:现代化路径处理
  20. 19异常处理
  21. 20dataclass
  22. 21上下文管理器(with)
  23. 22async / await
  24. 23pyproject.toml + uv
  25. 24ruff:一站式代码检查
  26. 25pytest:测试框架
  27. 26日志 logging
  28. 27打包发布到 PyPI
  29. 28学完之后
Python 环境加载中…

dataclass

4 道练习题·预计 80 分钟·做对一题解锁下一段

完整通读本章 →

教学 01 / 18· 已读

dataclass 与 Pydantic

写代码这事,一不留神就会陷入「样板代码」的泥潭。各位先别急着反驳,咱们做个小实验:现在请你写一个 Employee 类,要求是这样的——存员工的姓名、部门、工号、入职日期、月薪,要能正常打印(不能是 <__main__.Employee object at 0x...> 这种鬼东西),要能比较两个员工对象是否相等,最好还能拿出来做字典的 key。

听起来不难是吧?善于思考的你可能已经在心里默默写出来了,大概长这样:

Python· 可在网页运行
class Employee:
    def __init__(self, name, dept, emp_id, hire_date, salary):
        self.name = name
        self.dept = dept
        self.emp_id = emp_id
        self.hire_date = hire_date
        self.salary = salary

    def __repr__(self):
        return (
            f'Employee(name={self.name!r}, dept={self.dept!r}, '
            f'emp_id={self.emp_id!r}, hire_date={self.hire_date!r}, '
            f'salary={self.salary!r})'
        )

    def __eq__(self, other):
        if not isinstance(other, Employee):
            return NotImplemented
        return (
            self.name == other.name
            and self.dept == other.dept
            and self.emp_id == other.emp_id
            and self.hire_date == other.hire_date
            and self.salary == other.salary
        )

    def __hash__(self):
        return hash((self.name, self.dept, self.emp_id, self.hire_date, self.salary))


e = Employee('两点水', '做鸭事业部', 1001, '2020-03-15', 12000)
print(e)

输出:

文本
Employee(name='两点水', dept='做鸭事业部', emp_id=1001, hire_date='2020-03-15', salary=12000)

各位数一下,光这么一个普普通通的「数据类」,就花了二十多行。__init__ 写一遍字段,__repr__ 写一遍字段,__eq__ 写一遍字段,__hash__ 又写一遍字段——同一组字段名重复出现了五次。再想象一下你这个类有 15 个字段,那 __init__ 的参数列表就要排成一列火车,每个 self.xxx = xxx 都要复制粘贴,写到第十个就开始想骂人。

这就是所谓的「样板代码」。它没创造任何业务价值,纯粹是 Python 语法要求你必须这么写。写代码的人讨厌它,看代码的人也讨厌它,因为信息密度太低,真正重要的「这个类有哪些字段」被淹没在 self.xxx = xxx 的重复噪声里。

那有没有什么办法,能让我们只声明字段,剩下的活儿让 Python 自己干?

有。Python 3.7 给我们送来了 dataclass。从 3.10 起又给它加了 slots、kw_only 等更现代的开关。再往后还有第三方的 Pydantic,主打「带运行时校验的数据模型」。这一篇,咱们就把「轻量级数据类」这条线从 dataclass 一路捋到 Pydantic,让各位写数据结构的时候,再也不用手指头打结。

教学 02 / 18

第一个 dataclass,长什么样

把上面那个 Employee 类,用 dataclass 重写一遍:

Python· 可在网页运行
from dataclasses import dataclass


@dataclass
class Employee:
    name: str
    dept: str
    emp_id: int
    hire_date: str
    salary: int


e = Employee('两点水', '做鸭事业部', 1001, '2020-03-15', 12000)
print(e)

输出:

文本
Employee(name='两点水', dept='做鸭事业部', emp_id=1001, hire_date='2020-03-15', salary=12000)

各位看,二十多行的代码,缩成了不到十行。@dataclass 这个装饰器一贴,Python 就帮我们干了这些事:

  • 看到 name: str、dept: str 这些「带类型注解的类变量」,自动当成字段
  • 自动生成一个 __init__,参数顺序就是字段顺序
  • 自动生成一个 __repr__,长得跟咱们手写的那种「类名(字段=值, 字段=值)」一模一样
  • 自动生成一个 __eq__,按字段逐个比较

整个过程,你只需要把字段名和它的类型写出来,剩下的全是 dataclass 在帮你干活。

那「类型注解」是不是必须的?是的。这是 dataclass 识别字段的依据。你如果只写 name = '' 而不写 name: str,dataclass 就认不出来——它会把 name 当成一个普通的类属性,不会进 __init__ 的参数列表。

各位记住一句话:在 dataclass 里,name: str 是「字段声明」,name = '默认值' 是「类属性」,两者作用截然不同。

Python· 可在网页运行
from dataclasses import dataclass


@dataclass
class Demo:
    a: int        # 这是字段,会进 __init__
    b: int = 10   # 这是有默认值的字段,也会进 __init__
    c = 20        # 注意:这里没有类型注解,被当成普通类属性,不会进 __init__


d = Demo(1)
print(d)
print(d.c)

输出:

文本
Demo(a=1, b=10)
20

看到没?c 没出现在 repr 里,因为它根本不是一个字段,只是个挂在类上的常量。

练习 1 / 4·用 @dataclass 定义 Point题目有问题?

请用 @dataclass 装饰器定义一个 Point 类:

  • 两个字段:x: int、y: int
  • 然后实例化 Point(1, 2) 赋给变量 p,并 print(p)

输出应该是:

文本
Point(x=1, y=2)

(这正是 dataclass 自动生成的 __repr__ 输出。)

main.py
可编辑
🔒做对当前题解锁下一段 ·0/4

推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai

← 上一章19 · 异常处理
dataclass
下一章 →21 · 上下文管理器(with)
本章目录

dataclass

  1. 教学 01dataclass 与 Pydantic
  2. 教学 02第一个 dataclass,长什么样
  3. 练习 1用 @dataclass 定义 Point
  4. 教学 03 🔒比较两个 dataclass 对象
  5. 教学 04 🔒默认值——给字段一个偷懒的初始值
  6. 教学 05 🔒`field()`——字段的高级配置
  7. 练习 2 🔒可变默认值:default_factory
  8. 教学 06 🔒不可变 dataclass——`frozen=True`
  9. 练习 3 🔒frozen=True:不可变 + 可 hash
  10. 练习 4 🔒自动 __eq__:按字段值比较
  11. 教学 07 🔒`__post_init__`——构造完之后再算点东西
  12. 教学 08 🔒`kw_only=True`——强制关键字参数(Python 3.10+)
  13. 教学 09 🔒`slots=True`——让 dataclass 更省内存(Python 3.10+)
  14. 教学 10 🔒dataclass 跟继承
  15. 教学 11 🔒不止 dataclass——还有 NamedTuple 和 TypedDict
  16. 教学 12 🔒dataclass 的局限——它不做运行时校验
  17. 教学 13 🔒Pydantic 入场——带运行时校验的数据模型
  18. 教学 14 🔒dataclass vs Pydantic vs attrs——三选一指南
  19. 教学 15 🔒小实战——`Order` + `OrderRequest` 模拟一个下单接口
  20. 教学 16 🔒一点小提醒——dataclass 跟 Pydantic 的常见踩坑
  21. 教学 17 🔒小结
  22. 教学 18 🔒两份数据的默认列表是不是同一份

学习目录