python的dataclass详解
dataclass是python3.7引入的装饰器。dataclass 是一个代码生成器,它能帮你自动编写那些用于存储数据的类中“枯燥”的、重复性的方法,比如()、()、() 等。这样就可以让存储数据的类变动更简洁、更易读。1 不使用dataclass如果定义中不适用dataclass,我们需要如何定义一个存储数据的类呢?
dataclass是python3.7引入的装饰器。dataclass 是一个代码生成器,它能帮你自动编写那些用于存储数据的类中“枯燥”的、重复性的方法,比如 init()、repr()、eq() 等。这样就可以让存储数据的类变动更简洁、更易读。
1 不使用dataclass
如果定义中不适用dataclass,我们需要如何定义一个存储数据的类呢?
“传统”方式
class Point:
def init(self, x: float, y: float):
self.x = x
self.y = y
def __repr__(self):
# 为了方便调试,打印出易于理解的表示
return f"Point(x={self.x}, y={self.y})"
def __eq__(self, other):
# 为了能比较两个实例是否相等
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
使用它
p1 = Point(1.0, 2.0)
p2 = Point(1.0, 2.0)
print(p1) # 输出: Point(x=1.0, y=2.0)
print(p1 == p2) # 输出: True
在这个类中:
● init:只是把参数传递给实例的变量
● repr:定义了标准打印对象的时候能够看到有用的信息,而不是<main.Point object at 0x…>
● eq:为了能够正确的比较两个Point对象是不是相等。
2 使用dataclass
from dataclass import dataclass
@dataclass
class Point:
x:float
y:float
#使用
p1=Point(2.0,3.0)
p2=Point(2.0,3.0)
print(p1)# 输出Point(x=2.0,y=3.0),自动生成了 __repr__方法
print(p1=p2)#输出True,自动生成了__eq__方法
@dataclass装饰器自动的为Point生成了
● init(self, x: float, y: float)
● repr(self)
● eq(self, other)
3 dataclass的主要特性
3.1 提供默认值
@dataclass
class InventoryItem:
name: str
unit_price: float
quantity: int = 0 # 默认值为 0
item= InventoryItem(“apple”,1.5)
print(item)
输出:InventoryItem(name=‘apple’, unit_price=1.5, quantity=0)
3.2 field()实现更精细的控制
当你需要对某个字段进行更复杂的设置时,可以使用 field() 函数。一个常见的陷阱是在函数参数或类属性中使用可变的默认值(如 [] 或 {})。dataclass 通过 default_factory 解决了这个问题。
from dataclasses import field
from typing import List
@dataclass
class Team:
name: str
# 错误的方式: members: List[str] = []
# 这会导致所有 Team 实例共享同一个列表
# 正确的方式: 使用 default_factory
members: List[str] = field(default_factory=list)
t1 = Team(“Justice League”)
t1.members.append(“Superman”)
t2 = Team(“Avengers”)
print(t2.members) # 输出: [] (t2 有自己的独立列表)
default_factory 接受一个无参数的函数(比如 list、dict),每次创建新实例时,它会调用这个函数来生成一个全新的默认值。field() 的其他常用参数:
● init=False: 该字段不会被包含在 init 方法中,也不会在创建实例时传递。通常用于那些依赖其他字段计算得出的属性。
● repr=False: 该字段不会被包含在 repr 的输出中(例如,隐藏密码或大型数据)。
● compare=False: 该字段在 eq 和 lt 等比较方法中被忽略。
import math
@dataclass
class Circle:
radius: float
# 这个字段在创建实例后计算得出,不应在 init 中
area: float = field(init=False)
def __post_init__(self):
# __post_init__ 是一个特殊方法,在 __init__ 执行后被调用
# 非常适合用来处理 init=False 的字段
self.area = math.pi * (self.radius ** 2)
c = Circle(5.0)
print© # 输出: Circle(radius=5.0, area=78.53981633974483)
3.3 frozen=True不可变对象
使用frozen=True,可以让创建的实例变成不可变的。对于创建可靠的值对象是非常有用的,例如把对象用作字典的键时,它必须是可哈希的。frozen=True 的 dataclass 会自动生成 hash 方法。
@dataclass(frozen=True)
class ImmutablePoint:
x: int
y: int
p = ImmutablePoint(10, 20)
下面这行代码会引发 FrozenInstanceError 异常
p.x = 15
4 适用范围
如下的一些是dataclass适合的应用的情况:
● 纯数据容器:当你的类主要目的是捆绑一些数据字段时,dataclass 是完美的选择。例如:API响应、数据库记录、配置项。
● 替代 namedtuple:dataclass 提供了类型提示、默认值和更大的灵活性,是 collections.namedtuple 的现代替代品。
● 简化值对象(Value Objects):当你需要一个基于其值而不是其身份(ID)来比较的对象时,dataclass 的自动 eq 非常方便。
如果一个类主要包含方法,而不是数据,那么就不要用dataclass。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)