Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mypy more specific parameter in subclass

I want to declare a base class with an abstract method that has a typed parameter such that implementing classes can specify a more specific type for that parameter, for example:

from abc import ABC, abstractmethod

class Job(ABC):
    pass

class EasyJob(Job):
    pass

class HardJob(Job):
    pass

class Worker(ABC):
    @abstractmethod
    def run(self, job: Job) -> None:
        raise NotImplementedError()

class EasyWorker(Worker):
    def run(self, job: EasyJob) -> None:
        pass

class HardWorker(Worker):
    def run(self, job: HardJob) -> None:
        pass

However, mypy understandably complains about this:

line 14: error: Argument 1 of "run" is incompatible with supertype "Worker"; supertype defines the argument type as "Job"
line 18: error: Argument 1 of "run" is incompatible with supertype "Worker"; supertype defines the argument type as "Job"

Is there any way in Python to facilitate such a structure?

like image 590
Lukas Schmelzeisen Avatar asked Nov 27 '19 14:11

Lukas Schmelzeisen


People also ask

How do I reduce MYPY errors?

Silencing errors based on error codes You can use a special comment # type: ignore[code, ...] to only ignore errors with a specific error code (or codes) on a particular line. This can be used even if you have not configured mypy to show error codes.

Does MYPY make Python faster?

Will static typing make my programs run faster? # Mypy only does static type checking and it does not improve performance. It has a minimal performance impact.

Is MYPY slow?

Mypy runs are slow If your mypy runs feel slow, you should probably use the mypy daemon, which can speed up incremental mypy runtimes by a factor of 10 or more. Remote caching can make cold mypy runs several times faster.

What is MYPY?

“Mypy is an optional static type checker for Python that aims to combine the benefits of dynamic (or 'duck') typing and static typing. Mypy combines the expressive power and convenience of Python with a powerful type system and compile-time type checking.” A little background on the Mypy project.


1 Answers

You probably want Bounded Parametric Polymorphism. See also this section about bounded type variables.

In Worker, you want to say that your method run is generic in the sense that it takes a value of some unspecified type T whereas T is a subtype of Job. The classes derived from Worker then substitute T for concrete types:

from abc import ABC, abstractmethod
from typing import Generic, TypeVar


class Job(ABC):
    pass


class EasyJob(Job):
    pass


class HardJob(Job):
    pass

T = TypeVar('T', bound=Job)


class Worker(ABC, Generic[T]):
    @abstractmethod
    def run(self, job: T) -> None:
        raise NotImplementedError()


class EasyWorker(Worker[EasyJob]):
    def run(self, job: EasyJob) -> None:
        pass


class HardWorker(Worker[HardJob]):
    def run(self, job: HardJob) -> None:
        pass
like image 140
Martin Leinberger Avatar answered Oct 09 '22 09:10

Martin Leinberger