gpt4 book ai didi

返回子类实例的基类上的工厂方法的 Python 3 类型提示

转载 作者:太空狗 更新时间:2023-10-29 21:45:16 25 4
gpt4 key购买 nike

假设我有两个类 BaseChild使用 Base 中的工厂方法.工厂方法调用另一个可能被 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()返回了 Base 的实例和 Child.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 和所有...,这感觉相当不符合 Python 标准......

最佳答案

确实有可能:这个特征叫做TypeVar with Generic Self (虽然这有点误导,因为在这种情况下我们将它用于类方法)。我相信它的行为与您链接到的“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 的绑定(bind)设置为“Base”是可选的,但这可能是个好主意:这样,即使您不确切知道您正在处理哪个子类。
  3. 对于子定义,我们可以省略 cls 上的注解。

关于返回子类实例的基类上的工厂方法的 Python 3 类型提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46007544/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com