frozen=True 时如何设置__post_init__ 中dataclass 字段的值?

新手上路,请多包涵

我正在尝试创建一个冻结的数据类,但我在设置 __post_init__ 的值时遇到问题。在使用 frozen=True 设置时,有没有办法根据 init param 中的 dataclass 的值设置字段值?

 RANKS = '2,3,4,5,6,7,8,9,10,J,Q,K,A'.split(',')
SUITS = 'H,D,C,S'.split(',')

@dataclass(order=True, frozen=True)
class Card:
    rank: str = field(compare=False)
    suit: str = field(compare=False)
    value: int = field(init=False)
    def __post_init__(self):
        self.value = RANKS.index(self.rank) + 1
    def __add__(self, other):
        if isinstance(other, Card):
            return self.value + other.value
        return self.value + other
    def __str__(self):
        return f'{self.rank} of {self.suit}'

这就是踪迹

 File "C:/Users/user/.PyCharm2018.3/config/scratches/scratch_5.py", line 17, in __post_init__
    self.value = RANKS.index(self.rank) + 1
  File "<string>", line 3, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'value'

原文由 nicholishen 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 668
2 个回答

我在几乎所有类中使用的解决方案是将额外的构造函数定义为类方法。

根据给定的示例,可以将其重写如下:

 @dataclass(order=True, frozen=True)
class Card:
    rank: str = field(compare=False)
    suit: str = field(compare=False)
    value: int

    @classmethod
    def from_rank_and_suite(cls, rank: str, suit: str) -> "Card":
        value = RANKS.index(self.rank) + 1
        return cls(rank=rank, suit=suit, value=value)

有了这个,就可以拥有所需的所有自由,而不必诉诸 __setattr__ hack,也不必放弃所需的严格性,如 frozen=True

原文由 Max Görner 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题