Mypy 子类中更具体的参数

Posted

技术标签:

【中文标题】Mypy 子类中更具体的参数【英文标题】:Mypy more specific parameter in subclass 【发布时间】:2020-03-23 03:40:57 【问题描述】:

我想声明一个带有抽象方法的基类,该方法具有类型化参数,以便实现类可以为该参数指定更具体的类型,例如:

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

然而,mypy 抱怨这一点是可以理解的:

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"

在 Python 中有什么方法可以促进这样的结构吗?

【问题讨论】:

【参考方案1】:

你可能想要Bounded Parametric Polymorphism。另见this section about bounded type variables。

Worker 中,你想说你的方法 run 是通用的,因为它需要一个未指定类型的值 TTJob 的子类型。从 Worker 派生的类然后用 T 代替具体类型:

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

【讨论】:

我用上面的代码两次得到这个 mypy 错误:E1136: Value 'Worker' is unsubscriptable (unsubscriptable-object)

以上是关于Mypy 子类中更具体的参数的主要内容,如果未能解决你的问题,请参考以下文章

使用 TypeVar 在 MyPy 中使用参数键入装饰器会产生预期的无人居住类型

为啥为 __eq__ 定义参数类型会引发 MyPy 类型错误?

如何让 Mypy 在 Callable 中识别类的协议成员资格?

mypy:创建一个接受子类实例列表的类型

如何在java中传递命令行参数[重复]

柯里化函数的实现