【问题标题】:Calling generated `__init__` in custom `__init__` override on dataclass在自定义 `__init__` 中调用生成的 `__init__` 覆盖数据类
【发布时间】:2021-02-22 19:02:45
【问题描述】:

目前我有这样的事情:

@dataclass(frozen=True)
class MyClass:
  a: str
  b: str
  c: str
  d: Dict[str, str]

...除了dicts 是可变的,这一切都很好,所以我不能使用我的类来键入另一个字典。

相反,我希望字段 d 类似于 FrozenSet[Tuple[str, str]],但我仍然希望有人构造我的类的实例以便能够在构造函数上传递字典,因为这更多直观。

所以我想做类似的事情

@dataclass(frozen=True)
class MyClass:
  a: str
  b: str
  c: str
  d: FrozenSet[Tuple[str, str]] = field(init=False)

  def __init__(self, a, b, c, d: Dict[str, str]):
    self.original_generated_init(a, b, c)  # ???
    object.setattr(self, 'd', frozenset(d.items()))  # required because my dataclass is frozen

我如何实现这一目标?或者,是否有更优雅的方式来实现相同的目标?

【问题讨论】:

    标签: python python-3.x python-dataclasses


    【解决方案1】:

    您可以使用InitVar 并在__post_init__ 中分配给d

    @dataclass(frozen=True)
    class MyClass:
      a: str
      b: str
      c: str
      d: FrozenSet[Tuple[str, str]] = field(init=False)
      d_init: InitVar[Dict[str, str]]
    
      def __post_init__(self, d_init):
        object.__setattr__(self, 'd', frozenset(d_init.items()))
    

    【讨论】:

      【解决方案2】:

      a_guest 给出的答案是正确的,并且与基本数据类一样好,因为您始终必须解决他们设计为can't support type-validation or -conversion 的事实。如果你想干净地使用其中任何一个,你必须使用第三方库,如 attrsmarshmallowpydantic

      只是为了比较仅标准库的实现,我将向您展示您的数据类在 pydantic 中的外观。这是一个相对较新的框架,与其他两个相比,它的历史内容要少得多:

      from typing import FrozenSet, Tuple
      from pydantic import dataclasses, validator
      
      
      @dataclasses.dataclass(frozen=True)
      class Foo:
          a: str
          b: str
          c: str
          d: FrozenSet[Tuple[str, str]]
      
          @validator('d', pre=True)
          def d_accepts_dicts(cls, v):
              """Custom validator that allows passing dicts as frozensets.
              
              Setting the 'pre' flag means that it will run before basic type
              validation takes place, e.g. pydantic will not raise a TypeError
              for passing a dict instead of something natively consistent,
              like for example a list, or a frozenset.
              The code itself only checks if the argument passed as 'd' quacks
              like a dict, and transforms it if the answer is 'yes'.
              """
              try:
                  return frozenset(v.items())
              except AttributeError:
                  return v
      

      安装和使用另一个库会增加一些复杂性,但如果您经常觉得您的数据类需要我链接的初始列表中的某些内容(或 pydantic 的商标功能,运行时类型断言),那么这可能是值得的它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-26
        • 2020-02-01
        • 1970-01-01
        • 2016-04-19
        • 2022-01-24
        • 2016-03-20
        • 2014-02-14
        • 2021-01-17
        相关资源
        最近更新 更多