python-3.x - 您如何用mypy注释抽象类的类型?

标签 python-3.x types abstract-class mypy

我正在编写一个库,在这里我需要一个采用(可能)抽象类型的方法,并返回该类型的具体子类型的实例:

# script.py
from typing import Type
from abc import ABC, abstractmethod


class AbstractClass(ABC):
    @abstractmethod
    def abstract_method(self):
        pass

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

def f(c: Type[T]) -> T:
    # find concrete implementation of c based on
    # environment configuration
    ...


f(AbstractClass)  # doesn't type check

运行mypy script.py会产生:
error: Only concrete class can be given where "Type[AbstractClass]" is expected
我不明白此错误消息,并且很难找到有关该错误的任何文档。有什么方法可以注释该函数,以便mypy可以键入check this吗?

附带说明一下,PyCharm的类型检查器(这是我最常使用的类型)对f进行类型检查没有任何错误。

最佳答案

确实,mypy似乎有点偏爱以这种方式使用抽象基类,尽管您演示了有效的用例。

您可以通过使工厂函数成为抽象类上的类方法来解决此问题。从样式上讲,如果您想将顶级功能用作工厂,则可以为类方法创建一个别名。

from typing import TYPE_CHECKING
from abc import ABC, abstractmethod


class AbstractClass(ABC):
    @abstractmethod
    def abstract_method(self):
        raise NotImplementedError

    @classmethod
    def make_concrete(cls) -> 'AbstractClass':
        """
        find concrete implementation based on environment configuration
        """
        return A()


class A(AbstractClass):
    def abstract_method(self):
        print("a")

# make alias
f = AbstractClass.make_concrete
x = f()
if TYPE_CHECKING:
    reveal_type(x)  # AbstractClass

请注意,没有更多的工作,mypy无法知道工厂函数创建的具体类,它只会知道它与AbstractClass兼容,如reveal_type的输出所示。

或者,如果您愿意放弃abc.ABC提供的运行时检查,则可以获得与原始设计更加接近的东西:
from typing import TYPE_CHECKING
from abc import abstractmethod


class AbstractClass:  # do NOT inherit from abc.ABC
    @abstractmethod
    def abstract_method(self):
        raise NotImplementedError


class A(AbstractClass):
    def abstract_method(self):
        print("a")


class Bad(AbstractClass):
    pass


def f() -> AbstractClass:
    """
    find concrete implementation based on environment configuration
    """
    pass

b = Bad()  # mypy displays an error here:  Cannot instantiate abstract class 'Bad' with abstract attribute 'abstract_method'

x = f()
if TYPE_CHECKING:
    reveal_type(x)  # AbstractClass

这是可行的,因为mypy会检查标有@abstractmethod的方法,即使该类未从abc.ABC继承。但是请注意,如果您使用python执行程序,则在不实现其抽象方法的情况下,实例化Bad类将不再出错。

关于python-3.x - 您如何用mypy注释抽象类的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48349054/

相关文章:

python - 是否可以将文本隐藏在 Tkinter 的按钮/标签内?

Python:对象到str的隐式转换?

php - 哪种数据类型适合存储这种情况?

java - 如何使用基类设置标签?

Java:在子类中使用父类的静态方法

python-3.x - Flask Debug模式在使用 python 运行时给出 "OSError: [Errno 8] Exec format error"

Python3.6 import paramiko卡住了

c++ - 如何在编译时检查类是否是抽象的?

python-3.x - 如何对相关请求日志条目进行分组 GAE python 3.7 标准环境

scala - Scala 中的基本集合类型是什么?