假设我有两个类,Base
并且在中Child
有一个工厂方法Base
。factory方法调用另一个类方法,该类方法可以被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来说感觉很不合逻辑。
确实有可能:此功能称为具有通用自定义的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': ...
注意:
cls
子定义的注释。
太棒了,谢谢你!不幸的是,PyCharm现在将on上的私有方法
cls
视为访问另一个对象上的私有成员,但是mypy却按预期对待了。您可以在不实际覆盖继承方法的情况下更改其继承类型吗?.... stackoverflow.com/q/49583643/2823755
@wwii-回答您上面的问题,不,不是真的。针对您链接到的问题,可以通过使BaseRepository成为通用类来解决您的问题。基本上,您是在定义自定义集合,因此以与在Java或C#或任何其他方式中定义自定义集合相同的方式来解决问题。
cls: Type[T]
,那么我如何使用cls访问其他方法?cls.other_method()
(other_method
是Base
类的方法)不再起作用