如何为抽象类方法构造函数添加类型注释?

问题描述 投票:0回答:1

我想对充当构造函数的抽象类方法进行类型注释。例如,在下面的代码中,

ElementBase.from_data
意味着是一个抽象类方法构造函数。

tmp.py

from abc import abstractmethod, abstractclassmethod
import copy
from typing import TypeVar, Type

ElementT = TypeVar('ElementT', bound='ElementBase')

class ElementBase:
    data: int
    def __init__(self, data): self.data

    #@abstractmethod
    def get_plus_one(self: ElementT) -> ElementT:
        out = copy.deepcopy(self)
        out.data = self.data + 1
        return out

    @abstractclassmethod
    def from_data(cls: Type[ElementT], data: int) -> ElementT: # mypy error!!!
        pass

class Concrete(ElementBase):
    @classmethod
    def from_data(cls, data: int) -> 'Concrete': # mypy error!!!
        return cls(data)

但是,将 mypy 应用于此代码会显示以下错误。

tmp.py:18: error: The erased type of self "Type[tmp.ElementBase]" is not a supertype of its class "tmp.ElementBase"
tmp.py:23: error: Return type "Concrete" of "from_data" incompatible with return type <nothing> in supertype "ElementBase"

您有办法解决这个错误吗?另外,我特别困惑的是

get_plus_one
的部分不会导致错误,而只有
abstractclassmethod
的部分会导致错误。

仅供参考,我想让抽象方法构造函数通用,因为我想静态地确保

ElementBase
的所有子类在调用
from_data
时返回其类型的对象。

[编辑]注释掉

abstractmethod

python mypy python-typing
1个回答
3
投票

看起来

mypy
不理解
abstractclassmethod
装饰器。该装饰器自 Python 3.3 起已被弃用,因为
abstractmethod
classmethod
装饰器已更新为可以很好地协同工作。我认为如果您这样做,您的代码将正常工作:

@classmethod
@abstractmethod 
def from_data(cls: Type[ElementT], data: int) -> ElementT:
    pass

这与您的类型检查问题无关,但您可能还希望将

ElementBase
更改为从
abc.ABC
继承,或者如果您希望 Python 强制执行类的抽象性,则显式请求
abc.ABCMeta
元类。常规类不关心
abstractmethod
装饰器,因此正如所写,您将能够实例化
ElementBase
(或者如果它的
__init__
方法没有不相关的问题,您也可以)。

关于这种类型提示的另一个外围相关注释... PEP 673 将在 Python 3.11 中添加

typing.Self
,这将是方法引用其所调用的对象类型的便捷方式。它应该可以很好地与类方法配合使用,而不需要您跳过任何障碍。有了它,您就可以编写这个更简单版本的注释:

@classmethod
@abstractmethod
def from_data(cls, data: int) -> Self:
    pass
© www.soinside.com 2019 - 2024. All rights reserved.