Как сделать незамерзший датакласс замороженным, и наоборот? - PullRequest
1 голос
/ 10 мая 2019

Я хочу знать любой простой способ сделать нижеуказанный класс данных bar замороженным.

@dataclass
class Bar:
    foo: int
bar = Bar(foo=1)

Другими словами, я хочу следующую функцию some_fn_to_freeze

frozen_bar = some_fn_to_freeze(bar)
frozen_bar.foo = 2 # Error

А, обратная функция some_fn_to_unfreeze

bar = som_fn_to_unfrozen(frozen_bar)
bar.foo = 3 # not Error

Ответы [ 2 ]

2 голосов
/ 10 мая 2019

dataclass не имеет встроенной поддержки для этого. Замороженность отслеживается на уровне класса, а не для каждого экземпляра, и не поддерживается автоматическая генерация замороженных или незамерзающих эквивалентов классов данных.

Хотя вы можете попытаться что-то сделать для создания новых классов данных на лету, они очень плохо взаимодействуют с isinstance, == и другими вещами, с которыми вы хотели бы работать. Вероятно, безопаснее просто написать два класса данных и методы конвертации:

@dataclass
class Bar:
    foo: int
    def as_frozen(self):
        return FrozenBar(self.foo)

@dataclass(frozen=True)
class FrozenBar:
    foo: int
    def as_unfrozen(self):
        return Bar(self.foo)
1 голос
/ 10 мая 2019

Классы данных Python хороши, но пакет attrs является более гибкой альтернативой, если вы можете использовать стороннюю библиотеку. Например:

import attr

# Your class of interest.
@attr.s()
class Bar(object):
   val = attr.ib()

# A frozen variant of it.
@attr.s(frozen = True)
class FrozenBar(Bar):
   pass

# Three instances:
# - Bar.
# - FrozenBar based on that Bar.
# - Bar based on that FrozenBar.
b1 = Bar(123)
fb = FrozenBar(**attr.asdict(b1))
b2 = Bar(**attr.asdict(fb))

# We can modify the Bar instances.
b1.val = 777
b2.val = 888

# Check current vals.
for x in (b1, fb, b2):
    print(x)

# But we cannot modify the FrozenBar instance.
try:
    fb.val = 999
except attr.exceptions.FrozenInstanceError:
    print(fb, 'unchanged')

Выход:

Bar(val=888)
FrozenBar(val=123)
Bar(val=999)
FrozenBar(val=123) unchanged
...