MSH*_*MSH 3 python inheritance mypy python-typing
我的 mypy 遇到一些问题。
我有一个抽象类和一个继承它的类:
from __future__ import annotations
from abc import abstractmethod, ABC
from typing import Union
class Base(ABC):
@abstractmethod
def the_method(self, a_class: Union[Base, float, int]) -> None:
...
@abstractmethod
def other_method(self) -> None:
...
class MyClass(Base):
def __init__(self, something: str = "Hello") -> None:
self.something = something
def the_method(self, a_class: Union[MyClass, float, int]) -> None:
print(a_class)
def other_method(self) -> None:
print(self.something)
Run Code Online (Sandbox Code Playgroud)
我知道里氏替换原则。然而MyClass是 的一种类型,Base因为它继承自它。但mypy仍然会引发错误:
from __future__ import annotations
from abc import abstractmethod, ABC
from typing import Union
class Base(ABC):
@abstractmethod
def the_method(self, a_class: Union[Base, float, int]) -> None:
...
@abstractmethod
def other_method(self) -> None:
...
class MyClass(Base):
def __init__(self, something: str = "Hello") -> None:
self.something = something
def the_method(self, a_class: Union[MyClass, float, int]) -> None:
print(a_class)
def other_method(self) -> None:
print(self.something)
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
Base.the_method接受,因此子类至少Base也需要接受。如果我有,那应该被接受。目前,尚未被 接受。 Baseclass Foo(Base)MyClass.the_method
对于方法参数和返回类型,里氏替换的工作方向相反 - 超类可以用于参数,子类可以用于返回类型。
你有很多选择。例如,您可以MyClass.the_method接受Base
class MyClass(Base):
def the_method(self, a_class: Union[Base, float, int]) -> None:
...
Run Code Online (Sandbox Code Playgroud)
或者(评论中讨论了下一个示例是否也违反了 LSP ...无论哪种方式,mypy 对此都过于宽容)更改Base为接受封闭类的实例
from typing import Self
class Base(ABC):
@abstractmethod
def the_method(self, a_class: Union[Self, float, int]) -> None:
...
Run Code Online (Sandbox Code Playgroud)