有没有办法用 mypy 覆盖 python 中继承的类属性类型?

STe*_*kov 5 python mypy python-typing python-3.10

我编写了一个defaultdict可以default_factory使用 key 作为参数进行调用的子类。

from collections import defaultdict
from typing import TypeVar, Any, Callable, Generic

K = TypeVar('K')


class keydefaultdict(defaultdict, Generic[K]):
    ''' Drop-in replacement for defaultdict accepting key as argument '''

    default_factory: Callable[[], Any] | Callable[[K], Any] | None

    def __missing__(self, key: K) -> Any:
        if self.default_factory is None:
            raise KeyError(key)
        else:
            try:
                ret = self[key] = self.default_factory(key)
            except TypeError:  # try no-key signature
                ret = self[key] = self.default_factory()
            # if failed, let the error propagate as usual

            return ret
Run Code Online (Sandbox Code Playgroud)

mypy抱怨default_factory类型提示:

赋值中的类型不兼容(表达式的类型为“Callable[[], Any] | Callable[[K], Any] | None”,基类“defaultdict”将类型定义为“Optional[Callable[[], Any]]” )

有什么办法可以覆盖类型吗?mypy也在这一行上抱怨self.default_factory(...)- 参数太多(或参数太少)以及实例化该字典的地方(不兼容的类型):

data = keydefaultdict(lambda key: [key])
Run Code Online (Sandbox Code Playgroud)

“keydefaultdict”的参数 1 具有不兼容的类型“Callable[[Any], list[Any]]”;预期“可选[可调用[[],任何]]”

Bro*_*ark 5

这是预期的行为,因为您所描述的内容违反了里氏替换原则。有关更多详细信息,请参阅mypy 文档。

由于这个原因,用作defaultdict子类是一个坏主意。但是,如果您确实想解决这个问题(不推荐),您可以使用# type: ignore[override],如下所示:

default_factory: Callable[[], Any] | Callable[[K], Any] | None # type: ignore[override]
Run Code Online (Sandbox Code Playgroud)

如果您需要更多信息,请在mypy 文档中对此进行更详细的描述。

  • 我了解 LSP,当然,我只是想确定没有比“忽略”评论更好的方法。“不,你不能”也是一个有效的答案,所以无论如何谢谢,接受。我想无论如何我都会保留评论,因为这确实是一个很小的变化,只影响一种方法,手动重写将需要更多的努力(并且在我看来会不太直观),而且它是一个与父级完全兼容的直接替代品。 (3认同)