I'd like to copy an instance of a frozen dataclass, changing just one field ("functional update").
Here's what I tried
from dataclasses import dataclass, asdict
@dataclass(frozen = True)
class Pos:
start: int
end: int
def adjust_start(pos: Pos, delta: int) -> Pos:
# TypeError: type object got multiple values for keyword argument 'start'
return Pos(**asdict(pos), start = pos.start + delta)
adjust_start(Pos(1, 2), 4)
What I'm looking for:
dict
s?TypeError
: if there is a way to functionally update kwargs then that could work.In Scala, a functional update of a case class (Scala dataclass) can be done like this: pos.copy(start = pos.start + delta)
.
dataclasses.replace()
to the rescue.
dataclasses.replace(obj, /, **changes)
creates a new object of the same type asobj
, replacing fields with values fromchanges
.
import dataclasses
@dataclasses.dataclass(frozen=True)
class Pos:
start: int
end: int
def adjust_start(pos: Pos, delta: int) -> Pos:
return dataclasses.replace(pos, start=pos.start + delta)
p = adjust_start(Pos(1, 2), 4)
Personally, I might put adjust
on the dataclass itself:
import dataclasses
@dataclasses.dataclass(frozen=True)
class Pos:
start: int
end: int
def adjust(self, *, start: int, end: int) -> "Pos":
return dataclasses.replace(
self,
start=self.start + start,
end=self.end + end,
)
p = Pos(1, 2).adjust(start=4)