☰
Python 装饰器:@dataclass(二)
2026/10/22 7:32:24 网站建设 项目流程

一、field()的全部参数

field()用于对字段进行精细控制。参数如下:

from dataclasses import dataclass, field @dataclass class Example: a: int = field( default=0, # 默认值 default_factory=None, # 默认工厂(与 default 二选一) init=True, # 是否出现在 __init__ 参数中 repr=True, # 是否出现在 __repr__ 中 compare=True, # 是否参与 __eq__ 比较 hash=None, # 是否参与 __hash__(None 表示继承 compare) metadata=None, # 附加元数据 kw_only=False # 是否强制关键字参数(Python 3.10+) )

1.defaultvsdefault_factory

参数适用类型说明
default不可变对象数字、字符串、元组、None
default_factory可变对象或动态值列表、字典、集合、函数调用
# 不可变默认值:直接用 default count: int = field(default=0) # 可变默认值:必须用 default_factory items: list = field(default_factory=list) # 动态默认值:用工厂函数 created_at: str = field(default_factory=lambda: datetime.now().isoformat())

2.init=False:不参与初始化

@dataclass class User: name: str age: int # 不参与 __init__,只能通过其他方式赋值 created_at: str = field(default="", init=False) u = User("Alice", 25) # 不用传 created_at # u = User("Alice", 25, "2024") # 会报错

适用场景:字段由内部逻辑填充,不需要外部传入。

3.repr=False:隐藏敏感字段

@dataclass class User: name: str password: str = field(repr=False) # 不出现在 __repr__ 中 u = User("Alice", "secret123") print(u) # User(name='Alice'),密码不会打印

适用场景:密码、Token 等敏感信息。

4.compare=False:不参与比较

@dataclass class User: id: int name: str timestamp: float = field(compare=False) # 不参与 == 比较 u1 = User(1, "Alice", 100.0) u2 = User(1, "Alice", 200.0) print(u1 == u2) # True,timestamp 不参与比较

适用场景:时间戳、缓存字段等不需要比较的字段。

5.kw_only=True:强制关键字参数(Python 3.10+)

@dataclass class Point: x: int y: int = field(kw_only=True) # 必须用 y= 传 p = Point(1, y=2) # 正确 # p = Point(1, 2) # 报错

适用场景:参数多时,强制关键字传参,避免顺序错误。

6.metadata:附加元数据

@dataclass class Product: name: str = field(metadata={"description": "商品名", "max_length": 100}) price: float = field(metadata={"unit": "元"}) # 获取元数据 print(Product.__dataclass_fields__["name"].metadata) # {'description': '商品名', 'max_length': 100}

适用场景:配合序列化库、ORM、文档生成工具使用。

二、__post_init__:后置初始化

__init__自动生成后,如果需要在初始化后做额外处理,用__post_init__。

@dataclass class Rectangle: width: float height: float area: float = field(init=False) # 不通过 __init__ 传 def __post_init__(self): self.area = self.width * self.height r = Rectangle(3, 4) print(r.area) # 12.0

执行顺序:

  1. 自动生成的__init__赋值所有字段

  2. __post_init__被调用

  3. 完成初始化

常用场景:

  • 计算派生字段

  • 数据校验

  • 类型转换

@dataclass class User: name: str age: int def __post_init__(self): if self.age < 0: raise ValueError("年龄不能为负数") self.name = self.name.strip()

三、frozen=True:不可变数据类

frozen=True让实例创建后不能修改,类似tuple。

@dataclass(frozen=True) class Point: x: int y: int p = Point(1, 2) # p.x = 3 # FrozenInstanceError

1.frozen=True带来的特性

特性说明
不可修改修改字段抛FrozenInstanceError
可哈希自动生成__hash__,可作为字典键
线程安全不可变对象天生线程安全
p1 = Point(1, 2) p2 = Point(1, 2) d = {p1: "原点"} # 可作为字典键 print(d[p2]) # 原点

2.frozen=True的__post_init__陷阱

在frozen=True时,__post_init__里不能用self.x = ...,要用object.__setattr__:

@dataclass(frozen=True) class Circle: radius: float area: float = field(init=False) def __post_init__(self): # self.area = ... # FrozenInstanceError object.__setattr__(self, "area", 3.14 * self.radius ** 2)

3. 适用场景

场景说明
配置对象创建后不应修改
值对象如坐标、金额、颜色
字典键需要可哈希
多线程共享避免竞态条件

四、order=True:支持排序

order=True自动生成<、<=、>、>=方法,按字段顺序比较。

@dataclass(order=True) class Student: score: int name: str students = [ Student(85, "Bob"), Student(92, "Alice"), Student(78, "Charlie"), ] students.sort() for s in students: print(s) # Student(score=78, name='Charlie') # Student(score=85, name='Bob') # Student(score=92, name='Alice')

比较规则:按字段声明顺序,逐字段比较。

@dataclass(order=True) class Item: price: float name: str # 先比 price,price 相同再比 name

隐藏字段不参与排序:

@dataclass(order=True) class Item: price: float name: str = field(compare=False) # 不参与排序

五、@dataclass的继承

@dataclass支持继承,子类会合并父类的字段。

@dataclass class Person: name: str age: int @dataclass class Student(Person): school: str grade: int s = Student("Alice", 18, "清华", 3) print(s) # Student(name='Alice', age=18, school='清华', grade=3)

1. 字段顺序规则

子类的字段会追加到父类字段后面。

@dataclass class A: x: int @dataclass class B(A): y: int # B 的字段顺序:x, y

2. 默认值冲突问题

如果父类有默认值,子类字段必须有默认值:

@dataclass class A: x: int = 0 @dataclass class B(A): y: int # 报错:y 没有默认值,但父类 x 有默认值

原因:Python 要求有默认值的字段不能在无默认值字段之后。

解决方案:给子类字段也加默认值,或用kw_only=True。

@dataclass class B(A): y: int = 0 # # 或者 @dataclass class C(A): y: int = field(kw_only=True) # 强制关键字参数

3.frozen的继承

frozen=True和frozen=False不能混用:

@dataclass(frozen=True) class A: x: int @dataclass(frozen=False) # 报错 class B(A): y: int

规则:子类的frozen必须与父类一致。

@dataclassvs Pydantic vs attrs

维度@dataclassPydanticattrs
来源标准库第三方第三方
数据校验无强需配置
序列化无内置 JSON无
性能快中快
可变性frozen控制可配置可配置
类型转换无自动需配置
学习成本低中中
适用场景内部数据类API、配置、验证高性能、复杂需求

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询