使用抽象基类进行Python类型提示

10

我有一个带有方法的ABC,子类应该返回自己的类型,我正在尝试找出最佳的类型提示方式。例如:

from abc import ABC, abstractmethod

class Base(ABC):
    @abstractmethod
    def f(self): ## here i want a type hint for type(self)
        pass

class Blah(Base):
    def __init__(self, x: int):
        self.x = x

    def f(self) -> "Blah":
        return Blah(self.x + 1)

我能想到的最好的方法是这个,但有点繁重:

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

SELF = TypeVar["SELF"]

class Base(ABC, Generic[SELF]):

    @abstractmethod
    def f(self) -> SELF:
        pass

class Blah(Base["Blah"]):

    def __init__(self, x: int):
        self.x = x

    def f(self) -> "Blah":
        return Blah(self.x+1)

有没有更好/更清晰的方法?


你所需要的只是对 ABC 的前向引用。对于类方法,如果返回的是 cls 类型的实例,请参见 Can you annotate return type when value is instance of cls? - Martijn Pieters
1个回答

1
使用Python 3.7,通过从__future__导入注释来实现。
from __future__ import annotations

class Base():
    def f(self) -> Base: ## Here the type is Base since we can not guarantee it is a Blah
        pass

class Blah(Base):
    def __init__(self, x: int):
        self.x = x

    def f(self) -> Blah: ## Here we can be more specific and say that it is a Blah
        return Blah(self.x + 1)

2
谢谢您的回答。然而,这会强制你在每个子类中都覆盖 f,即使内容完全相同。 - mousetail
这将是一个问题,因为我们无法从“f”的返回值中调用仅在“Blah”上定义的其他方法。 - mousetail
我现在授予你赏金,除非有人现在给出更好的答案。你很好地回答了原始问题,而我的真正问题与此有足够大的不同,劫持这个问题可能不是正确的选择。 - mousetail
1
我也在基类中看到了def f(self: T) -> T:,其中T是一个TypeVar。这种方式,基类不需要成为通用类,它还可以与cls:Type[T]一起使用作为classmethod。 - PhilMacKay
在3.11+版本中,或者通过typing_extensions进行回溯,现在有了Self。https://docs.python.org/3/library/typing.html#typing.Self - undefined
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接