在数据类上的自定义“__init__”重写中调用生成的“__init__”

Utt*_*sed 6 python python-3.x python-dataclasses

目前我有这样的事情:

@dataclass(frozen=True)
class MyClass:
  a: str
  b: str
  c: str
  d: Dict[str, str]
Run Code Online (Sandbox Code Playgroud)

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

相反,我希望 fieldd类似于 a 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
Run Code Online (Sandbox Code Playgroud)

我该如何实现这一目标?或者有没有更优雅的方法来实现同样的事情?

a_g*_*est 8

您可以使用 anInitVar并分配给din __post_init__

@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()))
Run Code Online (Sandbox Code Playgroud)


Arn*_*rne 5

a_guest 给出的答案是正确的,并且与基本数据类一样好,因为您始终必须解决它们无法按设计支持类型验证或转换的事实。如果您想干净地使用其中任何一个,则必须使用第三方库,例如attrsmarshmallowpydantic

只是为了与仅 standardlib 的实现进行比较,我将向您展示您的数据类在 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
Run Code Online (Sandbox Code Playgroud)

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