I have the following Foo base class, and Bar that inherits from it:
class Foo:
def __init__(self, x: int) -> None:
self._x = x
def do(self, x: int) -> None:
pass
class Bar(Foo):
pass
If I override Foo.do in Bar, and change the type of the x parameter for something incompatible (that is, not more generic than int), then Mypy returns an error - which is of course what I expect.
class Bar(Foo):
def do(self, x: str) -> None:
pass
Error:
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)
However, if I override __init__ with an incompatible type for the argument, then Mypy accepts it:
class Bar(Foo):
def __init__(self, x: str) -> None:
self._x = 12
Mypy output:
Success: no issues found in 1 source file
It looks to me that overriding __init__ with incompatible types violates the LSP as well, since code like foo = Foo(12) does not type-check if we replace Foo with Bar.
Why does Mypy accept that I override __init__ with an incompatible type? Is __init__ treated differently from other methods?
Also, is Mypy right in doing so? Am I correct that this last Bar class violates the LSP?