簡體   English   中英

你如何用mypy注釋抽象類的類型?

[英]How do you annotate the type of an abstract class with 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可以鍵入檢查嗎?

作為旁注,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的輸出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

這是有效的,因為即使類不是從abc.ABC繼承的, abc.ABC也會檢查標有@abstractmethod方法。 但請注意,如果您使用 python 執行程序,您將不會再收到關於實例化Bad類而不實現其抽象方法的錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM