Search code examples
pythonabstract-classtype-hintingabc

Type-Hinting Child class returning self


Is there any way to type an abstract parent class method such that the child class method is known to return itself, instead of the abstract parent.

class Parent(ABC):
    @abstractmethod
    def method(self) -> [what to hint here]:
        pass

class Child1(Parent)
    def method(self):
        pass

    def other_method(self):
        pass

class GrandChild1(Child1)
    def other_method_2(self):
        pass

This is more to improve autocompletes for IDEs like PyCharm or VScode's python plugin.


Solution

  • So, the general approach is described in the docs here

    import typing
    from abc import ABC, abstractmethod
    
    T = typing.TypeVar('T', bound='Parent') # use string
    
    class Parent(ABC):
        @abstractmethod
        def method(self: T) -> T:
            ...
    
    class Child1(Parent):
        def method(self: T) -> T:
            return self
    
        def other_method(self):
            pass
    
    class GrandChild1(Child1):
        def other_method_2(self):
            pass
    
    reveal_type(Child1().method())
    reveal_type(GrandChild1().method())
    

    And mypy gives us:

    test_typing.py:22: note: Revealed type is 'test_typing.Child1*'
    test_typing.py:23: note: Revealed type is 'test_typing.GrandChild1*'
    

    Note, I had to keep using type-variables to get this to work, so when I originally tried to use the actual child class in the child class annotation, it (erroneously?) inherited the type in the grandchild:

    class Child1(Parent):
        def method(self) -> Child1:
            return self
    

    I'd get with mypy:

    test_typing.py:22: note: Revealed type is 'test_typing.Child1'
    test_typing.py:23: note: Revealed type is 'test_typing.Child1'
    

    Again, I am not sure if this is expected/correct behavior. The mypy documentation currently has a warning:

    This feature is experimental. Checking code with type annotations for self arguments is still not fully implemented. Mypy may disallow valid code or allow unsafe code.