If, for example, I have classmethod in the base class:
class BaseClass:
@classmethod
def from_list(cls, **kwargs):
return cls(**kwargs)
and I'm going to create SubClass with this it's own __init__().
How can I annotate classmethod to return not the BaseClass, but an object of the SubClass, without reimplementing from_list method?
I'm not sure how to do it with a class method, but you can easily do this with a helper function that serves as a factory function:
from typing import TypeVar, Type
class B:
pass
T = TypeVar('T', bound=B)
def foo(cls: Type[T]) -> T:
return cls()
class C(B):
pass
reveal_type(foo(C))
class D(C):
pass
reveal_type(foo(D))
The first reveal call shows a return value of type C, the second shows type D.
You _ought_ to be able to do this with a class method, by annotating the cls argument with Type[T], but I couldn't get that to work; that seems a bug in mypy (or at least a missing feature).
Thank for the example @gvanrossum. Also, thanks for the referenced issue, it contains solution for almost exactly the same problem. I'm closing the issue.
Coming in from Google so if anyone is looking, this will be possible in Python 3.7:
https://docs.python.org/dev/whatsnew/3.7.html#pep-563-postponed-evaluation-of-annotations
I don't think that PEP 563 has much bearing on this issue -- whatever you can do with PEP 563 you can do without it by adding quotes around the forward reference.
Coming in from Google so if anyone is looking, this will be possible in Python 3.7:
docs.python.org/dev/whatsnew/3.7.html#pep-563-postponed-evaluation-of-annotations
What Guido said: the issue isn't that you can't annotate the type when you _know_ the type. The issue is that you want to use cls as an annotation in arguments and/or for the return type of a @classmethod. There still seems no easy way of doing this apparently :/
Guido gave the solution to this in his first answer:
_T = TypeVar("_T")
class Foo:
@classmethod
def create(cls: Type[_T]) -> _T:
return cls()
Most helpful comment
Guido gave the solution to this in his first answer: