如何使非冻结数据类冻结,反之亦然?

Yoh*_*hei 6 python python-dataclasses

我想知道一种使数据类bar冻结的简单方法。

@dataclass
class Bar:
    foo: int
bar = Bar(foo=1)
Run Code Online (Sandbox Code Playgroud)

换句话说,我想要一个如下所示的函数some_fn_to_freeze

frozen_bar = some_fn_to_freeze(bar)
frozen_bar.foo = 2 # Error
Run Code Online (Sandbox Code Playgroud)

并且,反函数some_fn_to_unfreeze

bar = som_fn_to_unfrozen(frozen_bar)
bar.foo = 3 # not Error
Run Code Online (Sandbox Code Playgroud)

Con*_*tor 8

改变数据类的标准方法frozen是使用dataclasses.replace

old_bar = Bar(foo=123)
new_bar = dataclasses.replace(old_bar, foo=456)
assert new_bar.foo == 456
Run Code Online (Sandbox Code Playgroud)

对于更复杂的用例,您可以使用以下位置的 dataclass utils 模块:https: //github.com/google/etils

它添加一个my_dataclass = my_dataclass.unfrozen()成员,允许frozen直接改变数据类

# pip install etils[edc]
from etils import edc

@edc.dataclass(allow_unfrozen=True)  # Add the `unfrozen()`/`frozen` method
@dataclasses.dataclass(frozen=True)
class A:
  x: Any = None
  y: Any = None


old_a = A(x=A(x=A()))

# After a is unfrozen, the updates on nested attributes will be propagated
# to the top-level parent.
a = old_a.unfrozen()
a.x.x.x = 123
a.x.y = 'abc'
a = a.frozen()  # `frozen()` recursively call `dataclasses.replace`

# Only the `unfrozen` object is mutated. Not the original one.
assert a == A(x=A(x=A(x = 123), y='abc'))
assert old_a == A(x=A(x=A()))
Run Code Online (Sandbox Code Playgroud)

如示例中所示,您可以返回unfrozen/frozen复制数据类,该数据类被明确设计为改变嵌套数据类。

@edc.dataclass还向数据类添加一个a.replace(**kwargs)方法(别名dataclasses.dataclass

a = A()
a = a.replace(x=123, y=456)
assert a == A(x=123, y=456)
Run Code Online (Sandbox Code Playgroud)