STerliakov
STerliakov

Reputation: 7943

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

I wrote a defaultdict subclass that can call default_factory with key as argument.

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 complains on the default_factory type hint:

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

Is there any way to override the type? mypy complains also on this lines self.default_factory(...) - too many arguments (or too few arguments) and in places where this dict is instantiated (incompatible type):

data = keydefaultdict(lambda key: [key])

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

Upvotes: 8

Views: 7178

Answers (1)

BrokenBenchmark
BrokenBenchmark

Reputation: 19252

This is intended behavior, as what you're describing violates the Liskov substitution principle. See the mypy documentation for more details.

Using defaultdict as a subclass is a bad idea for this reason. But, if you really want to get around this (not recommended), you can use # type: ignore[override], like so:

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

This is described in further detail in the mypy documentation if you want more information.

Upvotes: 7

Related Questions