由于属性协方差,如何避免 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
** 我选择的解决方案的原因是:
- 尽管
cast
并没有真正做任何事情(定义为 pass
),但它是 linters 知道输入中发生了某些变化的一种方式,所以你不会得到一个错误。而且,pass
,它的成本几乎可以忽略不计。
- 任何阅读代码的人都清楚地知道正在发生的事情。
- 模仿您在 C++(一种硬类型语言)中执行此操作的方式,这有点是我的目标之一,以遵循硬类型方法。
我试图避免在代码示例的最后一行显示为注释的 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
** 我选择的解决方案的原因是:
- 尽管
cast
并没有真正做任何事情(定义为pass
),但它是 linters 知道输入中发生了某些变化的一种方式,所以你不会得到一个错误。而且,pass
,它的成本几乎可以忽略不计。 - 任何阅读代码的人都清楚地知道正在发生的事情。
- 模仿您在 C++(一种硬类型语言)中执行此操作的方式,这有点是我的目标之一,以遵循硬类型方法。