Starting with Python 3.11 you can use the new typing.Self
object. For older Python versions you can get the same object by using the typing-extensions
project:
try:
from typing import Self
except ImportError:
from typing_extensions import Self
class TrivialClass:
# ...
@classmethod
def from_int(cls, int_arg: int) -> Self:
# ...
return cls(...)
Note that you don't need to annotate cls
in this case.
Warning: mypy support for the Self
type has not yet been released; you'll need to wait for the next version after 0.991. Pyright already supports it.
If you can't wait for Mypy support, then you can use a generic type to indicate that you'll be returning an instance of cls
:
from typing import Type, TypeVar
T = TypeVar('T', bound='TrivialClass')
class TrivialClass:
# ...
@classmethod
def from_int(cls: Type[T], int_arg: int) -> T:
# ...
return cls(...)
Any subclass overriding the class method but then returning an instance of a parent class (TrivialClass
or a subclass that is still an ancestor) would be detected as an error, because the factory method is defined as returning an instance of the type of cls
.
The bound
argument specifies that T
has to be a (subclass of) TrivialClass
; because the class doesn't yet exist when you define the generic, you need to use a forward reference (a string with the name).
See the Annotating instance and class methods section of PEP 484.
Note: The first revision of this answer advocated using a forward reference
naming the class itself as the return value, but issue 1212 made it possible to use generics instead, a better solution.
As of Python 3.7, you can avoid having to use forward references in annotations when you start your module with from __future__ import annotations
, but creating a TypeVar()
object at module level is not an annotation. This is still true even in Python 3.10, which defers all type hint resolution in annotations.