【发布时间】:2021-11-22 10:46:30
【问题描述】:
我有以下Foo 基类和继承自它的Bar:
class Foo:
def __init__(self, x: int) -> None:
self._x = x
def do(self, x: int) -> None:
pass
class Bar(Foo):
pass
如果我在Bar 中覆盖Foo.do,并为不兼容的东西更改x 参数的类型(也就是说,不比int 更通用),那么Mypy 会返回一个错误——这当然是我的期望。
class Bar(Foo):
def do(self, x: str) -> None:
pass
错误:
test.py:10: error: Argument 1 of "do" is incompatible with supertype "Foo"; supertype defines the argument type as "int"
test.py:10: note: This violates the Liskov substitution principle
test.py:10: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
Found 1 error in 1 file (checked 1 source file)
但是,如果我使用不兼容的参数类型覆盖 __init__,那么 Mypy 会接受它:
class Bar(Foo):
def __init__(self, x: str) -> None:
self._x = 12
Mypy 输出:
Success: no issues found in 1 source file
在我看来,用不兼容的类型覆盖 __init__ 也违反了 LSP,因为如果我们将 Foo 替换为 Bar,像 foo = Foo(12) 这样的代码不会进行类型检查。
为什么 Mypy 接受我用不兼容的类型覆盖 __init__? __init__ 的处理方式是否与其他方法不同?
另外,Mypy 这样做对吗?最后一个 Bar 类违反了 LSP,我是否正确?
【问题讨论】:
-
请注意,如果您在
Bar中实际使用self._x = x或super().__init__(x),则会 被捕获。它是否违反 LSP 是一个有趣的问题 - classBar不能换成Foo,但它们的 instances 是兼容的。
标签: python types mypy python-typing liskov-substitution-principle