跳转到主要内容
模块 9 · 第 2 课(共 4)课程中的34/36~12 min
模块课程(2/4)

dataclass:没有样板的数据类

@dataclass 装饰器(dataclasses 模块)自动生成 __init__、__repr__ 和 __eq__ 用于唯一作用是 hold 的类 数据。更少的样板,更清晰的代码。

没有数据类(样板)

Python
class Punto:
    def __init__(self, x: float, y: float) -> None:
        self.x = x
        self.y = y
    def __repr__(self) -> str:
        return f"Punto(x={self.x}, y={self.y})"
    def __eq__(self, other) -> bool:
        if not isinstance(other, Punto):
            return NotImplemented
        return (self.x, self.y) == (other.x, other.y)

带数据类

Python
from dataclasses import dataclass

@dataclass
class Punto:
    x: float
    y: float

p = Punto(3, 4)
p             # Punto(x=3, y=4)   ← __repr__ gratis
Punto(3, 4) == Punto(3, 4)        # True ← __eq__ gratis
p.x, p.y      # 3, 4

模式:将字段声明为类注释 (name: type), 可选择使用默认值。 @dataclass 生成其余部分。

默认和default_factory

Python
from dataclasses import dataclass, field

@dataclass
class Articolo:
    nome: str
    prezzo: float = 0.0
    tag: list[str] = field(default_factory=list)

冻结=真:不可变

Python
@dataclass(frozen=True)
class Coordinata:
    lat: float
    lon: float

c = Coordinata(45.4, 9.2)
c.lat = 99   # FrozenInstanceError!

frozen 数据类也是 可哈希:您可以将它们用作字典键 或设置元素。

order=True:自动比较

Python
@dataclass(order=True)
class Voto:
    valore: int

Voto(10) < Voto(20)   # True
sorted([Voto(30), Voto(10), Voto(20)])

生成 __lt__、__le__、__gt__、__ge__ 按顺序比较字段 他们被宣布了。

普通方法

数据类仍然是常规类:您可以添加方法。

Python
import math
from dataclasses import dataclass

@dataclass
class Punto:
    x: float
    y: float
    def distanza_dall_origine(self) -> float:
        return math.hypot(self.x, self.y)

Punto(3, 4).distanza_dall_origine()   # 5.0

不可变且高效的数据类

您可以通过将参数 frozen=True 传递给装饰器:@dataclass(frozen=True) 来使数据类不可变。这会在实例化后尝试改变属性时引发错误,从而使实例对于并发环境或用作字典键是安全的。

自己尝试一下

锻炼#python.m9.l2.e1
尝试:0加载中...

创建一个数据类“Book”,其中包含字段“title: str”和“pages: int”。将其实例化为 `l = Book('Moby Dick', 635)`。评估 `l == Book('Moby Dick', 635)`。

正在加载编辑器...
显示提示

@dataclass 生成逐个字段比较的 __eq__ 。

3 次尝试后可用的解决方案

复习练习

锻炼#python.m9.l2.e2
尝试:0加载中...

创建一个数据类“Basket”,其中包含字段“items: list[str]”,default_factory=list。实例化 `c1 = Basket()` 和 `c2 = Basket()`,将 'mela' 附加到 c1.items。评估“(c1.items, c2.items)”以验证它们不是同一个列表。

正在加载编辑器...
显示提示

field(default_factory=list) 保证每个实例都有一个新列表。

3 次尝试后可用的解决方案

额外的挑战

锻炼#python.m9.l2.e3
尝试:0加载中...

Import `dataclass` from `dataclasses`. Create a dataclass `Point` containing two float coordinates `x` and `y`. Instantiate a point with `x=1.5` and `y=2.5` storing it in `p`. Finally, evaluate `p`.

正在加载编辑器...
显示提示

在 Point 类上方使用 @dataclass,并声明 x: float 和 y: float。

3 次尝试后可用的解决方案