A pattern that I find often appears in code is methods that must return a value that is of the same type as the self parameter.
For example, suppose you wanted to define a cloneable interface. The output of cloneable should itself be cloneable, so you may define the base class like this:
class Cloneable(metaclass=abc.ABCMeta):
@abc.abstractmethod
def clone(self) -> 'Cloneable'
pass
But this doesn't really capture the intention of a clone method. We don't want just any cloneable to come out, we want a clone of the same type. If you clone a list, you want a list. If you clone a tuple, you want a tuple, etc. In other words, you want this:
TSelf = TypeVar('TSelf')
class Cloneable(metaclass=abc.ABCMeta):
@abc.abstractmethod
def clone(self: TSelf) -> TSelf
pass
or this:
from typing import SelfType
class Cloneable(metaclass=abc.ABCMeta):
@abc.abstractmethod
def clone(self) -> SelfType
pass
Currently, attempting to use this pattern will not quite work with mypy (of course). For example, in the following code mypy will complain that "TSelf" has no attribute "factor":
TSelf = TypeVar('TSelf')
class Scaleable(metaclass=abc.ABCMeta):
@abc.abstractmethod
def scale(self: TSelf, factor: float) -> TSelf:
pass
class Eg(Scaleable):
def __init__(self, factor):
self.factor = factor
def scale(self: TSelf, factor: float) -> TSelf:
if self.factor == 0:
return self
return Eg(factor * self.factor)
I see two possible solutions to this:
SelfType value to typing. mypy could then recognize this value and apply appropriate specialized rules.self is annotated with a type variable, do not infer that this means class methods are not available.They both probably involve some pretty deep-down refactoring.
I don't want to disappoint you, but all this writing was in vain. This feature is already supported (modulo few bugs), see http://mypy.readthedocs.io/en/latest/generics.html#generic-methods-and-generic-self :-)
In particular your error is because you didn't add a suitable bound=... in your self-type variable, see the docs.
Most helpful comment
I don't want to disappoint you, but all this writing was in vain. This feature is already supported (modulo few bugs), see http://mypy.readthedocs.io/en/latest/generics.html#generic-methods-and-generic-self :-)