由于属性协方差,如何避免 child class 中的警告?

How can I avoid a warning in a child class due to attribute covariance?

我试图避免在代码示例的最后一行显示为注释的 linter 警告。

我明白为什么会这样,我知道我完全可以忽略,因为这是 Python。但是作为一种self-exercise,我一直在想一个正确的类型来避免它,但一直未能找到解决方案。

这是一个代码示例:

class Content(ABC):
    def __init__(self, data: Dict):
        self._data: Dict = data


class AlertContent(Content):
    def __init__(self, alert: Alert):
        data: Dict = get_data_from_alert(alert)
        super().__init__(data)
        self.alert_priority: str = alert.priority


class Envelope(ABC):
    def __init__(self, content: Content):
        self._content: Content = content
    
    @property
    @abstractmethod
    def priority(self) -> str:
        raise NotImplementedError


class AlertEnvelope(Envelope):
    def __init__(self, content: AlertContent):
        super().__init__(content)

    @property
    @abstractmethod
    def priority(self) -> str:
        return self._content.alert_priority  # Warning: Unresolved attribute reference 'alert_priority' for class 'Content'

你有什么想法吗?

我认为这涉及风格问题,但有争议的是,由于准确输入是您设计的一部分,您实际上并不需要 super().__init__(content),因为您正在构建 class 依赖于 AlertContent 的具体接口,而父 class 显式地使用不实现该接口的更抽象类型的属性。

因此,

class AlertEnvelope(Envelope):
    def __init__(self, content: AlertContent):
        self._content: AlertContent = content

考虑到您的目标,可能仍然是 DRY 代码。

我最终采用了以下解决方案:

class AlertEnvelope(Envelope):
    def __init__(self, content: AlertContent):
        super().__init__(content)

    # Inherited from Envelope
    # @property
    # def content(self) -> Content:
    #     return self._content

    def alert_content(self) -> AlertContent:
        return cast(AlertContent, self._content) # ** Reasoning below 

    @property
    @abstractmethod
    def priority(self) -> str:
        return self.alert_content.alert_priority

** 我选择的解决方案的原因是:

  1. 尽管 cast 并没有真正做任何事情(定义为 pass),但它是 linters 知道输入中发生了某些变化的一种方式,所以你不会得到一个错误。而且,pass,它的成本几乎可以忽略不计。
  2. 任何阅读代码的人都清楚地知道正在发生的事情。
  3. 模仿您在 C++(一种硬类型语言)中执行此操作的方式,这有点是我的目标之一,以遵循硬类型方法。