替换 Data Class 对象中的属性

Replace attributes in Data Class objects

我想替换 dataclass 实例的属性,类似于 namedtuple._replace(),即制作原始对象的更改副本:

from dataclasses import dataclass
from collections import namedtuple

U = namedtuple("U", "x")

@dataclass
class V:
    x: int

u = U(x=1)
u_ = u._replace(x=-1)
v = V(x=1)

print(u)
print(u_)
print(v)

这个returns:

U(x=1)
U(x=-1)
V(x=1)

如何在数据类对象中模拟此功能?

dataclass 只是语法糖,用于自动创建特殊的 __init__ 方法和许多其他基于类型注释属性的 "boilerplate" 方法。

一旦class被创建,它就像其他任何东西一样,它的属性可以被覆盖并且实例可以被复制,例如

import copy

v_ = copy.deepcopy(v)
v_.x = -1

根据属性的不同,您可能只需要 copy.copy

dataclasses 模块有一个辅助函数,用于实例 (docs) 的字段替换

from dataclasses import replace

用法不同于 collections.namedtuple,其中功能由生成类型的方法提供(旁注: namedtuple._replace 是 documented/public API,在名称上使用下划线被作者称为“遗憾”,请参阅答案末尾的link。

>>> from dataclasses import dataclass, replace
>>> @dataclass
... class V:
...     x: int
...     y: int
...     
>>> v = V(1, 2)
>>> v_ = replace(v, y=42)
>>> v
V(x=1, y=2)
>>> v_
V(x=1, y=42)

有关设计的更多背景信息,请参阅 PyCon 2018 演讲 - Dataclasses: The code generator to end all code generators。深入讨论了 replace API,以及 namedtupledataclasses 之间的其他设计差异,并显示了一些性能比较。

我知道问题是关于 dataclass,但是如果您使用的是 attr.s,那么您可以使用 attr.evolve 而不是 dataclasses.replace

import attr

@attr.s(frozen=True)
class Foo:
    x = attr.ib()
    y = attr.ib()

foo = Foo(1, 2)
bar = attr.evolve(foo, y=3)
@dataclass()
class Point:
    x: float = dataclasses.Field(repr=True, default=0.00, default_factory=float, init=True, hash=True, compare=True,
                                 metadata={'x_axis': "X Axis", 'ext_name': "Point X Axis"})
    y: float = dataclasses.Field(repr=True, default=0.00, default_factory=float, init=True, hash=True, compare=True,
                                 metadata={'y_axis': "Y Axis", 'ext_name': "Point Y Axis"})

Point1 = Point(13.5, 455.25)
Point2 = dataclasses.replace(Point1, y=255.25)

print(Point1, Point2)