gpt4 book ai didi

python - Mypy 在 __init__ 覆盖中接受不兼容的类型

转载 作者:行者123 更新时间:2023-12-04 14:03:07 25 4
gpt4 key购买 nike

我有以下 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 参数的类型更改为不兼容的内容(即,不超过generic than 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 = Foo(12) 这样的代码不会进行类型检查FooBar

为什么 Mypy 接受我用不兼容的类型覆盖 __init____init__ 与其他方法的处理方式不同吗?另外,Mypy 这样做对吗?我是否正确认为最后一个 Bar 类违反了 LSP?

最佳答案

Liskov 替换原则通常不被认为适用于构造函数方法。如果我们将构造函数方法视为对象接口(interface)的一部分,那么在许多情况下,继承系统将变得极其难以管理,并导致一大堆其他的复杂情况。参见 this question我前阵子在软件工程上发过照片。

然而,情况有点复杂,因为 __init__ 不是 真正的构造函数方法(应该是 __new__) — 它是一个初始化方法,可以在同一个实例上多次调用。初始化方法几乎总是与构造方法具有相同的签名只是“碰巧”的情况。

由于 __init__ 可以在同一个实例上多次调用,就像被视为对象接口(interface)一部分的“普通”方法一样,目前有 active discussion核心开发人员就 __init__ 方法是否应该在某些方面被视为对象接口(interface)的一部分进行讨论。

总结: ¯\_(ツ)_/¯

Python 是一种极度的动态语言,这意味着对其类型系统的推理通常会有些奇怪。

关于python - Mypy 在 __init__ 覆盖中接受不兼容的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69394820/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com