It is indeed possible: the feature is called TypeVar with Generic Self (though this is slightly misleading because we’re using this for a class method in this case). I believe it behaves roughly equivalently to the “CRTP” technique you linked to (though I’m not a C++ expert so can’t say for certain).
In any case, you would declare your base and child classes like so:
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': ...
Note that:
- We don’t need to make the class itself generic since we only need a generic function
- Setting the TypeVar’s bound to ‘Base’ is strictly speaking optional, but is probably a good idea: this way, the callers of your base class/subclasses will at least be able to call methods defined in the base class even if you don’t know exactly which subclass you’re dealing with.
- We can omit the annotation on
cls
for the child definition.