温馨提示:本文翻译自stackoverflow.com,查看原文请点击:其他 - Python 3 type hint for a factory method on a base class returning a child class instance

其他 - 返回基类的基类的工厂方法的Python 3类型提示

发布于 2020-03-27 12:07:20

假设我有两个类,Base并且在中Child有一个工厂方法Basefactory方法调用另一个类方法,该类方法可以被Base的子类覆盖

class Base(object):
    @classmethod
    def create(cls, *args: Tuple) -> 'Base':
        value = cls._prepare(*args)
        return cls(value)

    @classmethod
    def _prepare(cls, *args: Tuple) -> Any:
        return args[0] if args else None

    def __init__(self, value: Any) -> None:
        self.value = value


class Child(Base):
    @classmethod
    def _prepare(cls, *args: Tuple) -> Any:
        return args[1] if len(args) > 1 else None

    def method_not_present_on_base(self) -> None:
        pass

有没有一种注释的方法,Base.create以便静态类型检查器可以推断出Base.create()返回的实例BaseChild.create()返回的实例Child,以便下面的示例通过静态分析?

base = Base.create(1)
child = Child.create(2, 3)
child.method_not_present_on_base()

在上面的示例中,静态类型检查器会正确地抱怨类中method_not_present_on_base不存在Base


我考虑过要Base变成一个通用类,并让子类将自己指定为类型参数,即将CRTP引入Python。

T = TypeVar('T')

class Base(Generic[T]):
    @classmethod
    def create(cls, *args: Tuple) -> T: ...

class Child(Base['Child']): ...

但这对于来自C ++和所有其他语言的CRTP来说感觉很不合逻辑。

查看更多

查看更多

提问者
PoByBolek
被浏览
14
Michael0x2a 2017-09-06 06:41

确实有可能:此功能称为具有通用自定义的TypeVar(尽管这有点误导,因为在这种情况下,我们将其用于类方法)。我相信它的行为与您所链接的“ CRTP”技术大致相当(尽管我不是C ++专家,所以不能肯定地说)。

无论如何,您都可以这样声明基类和子类:

from typing import TypeVar, Type, Tuple

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

class Base:
    @classmethod
    def create(cls: Type[T], *args: Tuple[Any]) -> T: ...

class Child(Base):
    @classmethod
    def create(cls, *args: Tuple[Any]) -> 'Child': ...

注意:

  1. 我们不需要使类本身通用,因为我们只需要通用函数
  2. 将TypeVar的绑定设置为'Base'严格来说是可选的,但可能是一个好主意:这样,您的基类/子类的调用者至少可以调用基类中定义的方法,即使您不这样做也是如此。确切知道您要处理的是哪个子类。
  3. 我们可以省略cls子定义的注释

发布
问题

分享
好友

手机
浏览

扫码手机浏览