Mypy: Feature request: support for SelfType

Created on 29 Jun 2018  路  2Comments  路  Source: python/mypy

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:

  1. Add a SelfType value to typing. mypy could then recognize this value and apply appropriate specialized rules.
  2. When 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.

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 :-)

All 2 comments

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.

Was this page helpful?
0 / 5 - 0 ratings