有什么方法可以用 mypy 覆盖 python 中继承的 class 属性类型吗?

Is there any way to override inherited class attribute type in python with mypy?

我写了一个 defaultdict 子类,它可以调用 default_factory 并将键作为参数。

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

mypy 抱怨 default_factory 类型提示:

incompatible type in assignment (expression has type "Callable[[], Any] | Callable[[K], Any] | None", base class "defaultdict" defined the type as "Optional[Callable[[], Any]]")

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

data = keydefaultdict(lambda key: [key])

Argument 1 to "keydefaultdict" has incompatible type "Callable[[Any], list[Any]]"; expected "Optional[Callable[[], Any]]"

这是有意为之的行为,因为您所描述的内容违反了 Liskov substitution principle. See the mypy documentation 以获取更多详细信息。

出于这个原因,使用 defaultdict 作为子类不是一个好主意。但是,如果你真的想解决这个问题(不推荐),你可以使用# type: ignore[override],像这样:

default_factory: Callable[[], Any] | Callable[[K], Any] | None # type: ignore[override]

如果您想了解更多信息,the mypy documentation 中对此进行了更详细的描述。