问题描述
我有一个超类,它有一个由其子类共享的方法。但是,此方法应返回一个对象,其类型在子类上定义。我希望方法的返回类型是静态注释的(不是动态类型),以便使用子类的代码可以受益于 mypy
对返回值的类型检查。但是我不想为了提供它的类型注释而重新定义子类上的通用方法。使用 python 类型注释和 mypy 可以实现吗?
像这样:
from typing import Type
class AbstractModel:
pass
class OrderModel(AbstractModel):
def do_order_stuff():
pass
class AbstractRepository:
model: Type[AbstractModel]
def get(self) -> model:
return self.model()
class OrderRepository(AbstractRepository):
model = OrderModel
repo = OrderRepository()
order = repo.get()
# Type checkers (like mypy) should recognize that this is valid
order.do_order_stuff()
# Type checkers should complain about this; because `OrderModel`
# does not define `foo`
order.foo()
这里的棘手之处在于 get()
是在超类 AbstractRepository
上定义的,它还不知道 model
的类型。 (并且 -> model
注释失败,因为尚未指定 model
的值)。
model
的值由子类指定,但子类没有(重新)定义 get()
以提供注释。看起来这应该是静态可分析的;虽然这有点棘手,因为它需要静态分析器跟踪从超类到子类的 model
引用。
有什么方法可以同时实现共享超类实现和精确的子类返回类型?
解决方法
将 AbstractRepository
定义为泛型类。
from typing import TypeVar,Generic,Type,ClassVar
T = TypeVar('T')
class AbstractRespotitory(Generic[T]):
model: ClassVar[Type[T]]
@classmethod
def get(cls) -> T:
return cls.model()
(get
仅使用类属性,因此可以——而且可以说应该——是类方法。)