【问题标题】:Child dataclass with constant?具有常量的子数据类?
【发布时间】:2021-12-28 22:37:24
【问题描述】:
class MessageType(Enum):
    HELLO = 10

@dataclass(frozen=True)
class Message:
    op: MessageType

@dataclass(frozen=True)
class Hello(Message):
    op: MessageType.HELLO = field(init=False)
    foo: str

HelloMessage 的一种类型,操作码为 10。我想将所有传入消息转换为子类消息,以便函数能够识别类型:def process_hello(msg: Hello): m.foo + 123 将无法通过类型检查,但如果我们使用通用的Message 类型。

op: MessageType.HELLO = field(init=False, default=MessageType.HELLO)

这似乎可行,但代价是冗余指定MessageType.HELLO,这意味着允许自定义操作值。有没有更多的 Python 方法来做到这一点?

【问题讨论】:

  • MessageType.HELLO 不是类型;它是MessageType 类型的
  • Pylance 没问题,类型显示为Literal[MessageType.HELLO],好像正确?
  • 这可能是 Pylance 特有的行为;我不知道其他类型检查器是否会这样做。
  • 至少,您可以具体并自己使用Literal,而不是假设它会被推断出来。

标签: python enums typing python-dataclasses


【解决方案1】:

这在“初始化后处理”下的文档中进行了介绍

dataclass()生成的__init__()方法不调用基类__init__()方法。如果基类有必须调用的__init__() 方法,则通常在__post_init__() 方法中调用此方法:

在你的情况下,

@dataclass(frozen=True)
class Message:
    op: MessageType


@dataclass(frozen=True)
class Hello(Message):
    op: MessageType = field(init=False)
    foo: str

    def __post_init__(self):
        super().__init__(MessageType.HELLO)

不幸的是,似乎有必要重新定义 op 以不传递给 Hello.__init__

【讨论】:

  • 这与field(init=False, default=MessageType.HELLO)相比如何?
  • default 暗示如果您愿意,您可以提供一个(不同的)值,这在这种情况下没有意义。 (事实上​​,它不是 __init__ 的参数,这在一定程度上缓解了这种担忧。)
猜你喜欢
  • 2015-10-16
  • 1970-01-01
  • 2011-12-27
  • 1970-01-01
  • 2015-10-18
  • 2013-05-03
  • 2019-03-28
  • 1970-01-01
  • 2020-05-11
相关资源
最近更新 更多