pythonooppython-typingmethod-signature

Python overriding type hint on a method's return in child class, without redefining method signature


I have a base class with a type hint of float on a method's return.

In the child class, without redefining the signature, can I somehow update the type hint on the method's return to be int?


Sample Code

#!/usr/bin/env python3.6


class SomeClass:
    """This class's some_method will return float."""

    RET_TYPE = float

    def some_method(self, some_input: str) -> float:
        return self.RET_TYPE(some_input)


class SomeChildClass(SomeClass):
    """This class's some_method will return int."""

    RET_TYPE = int


if __name__ == "__main__":
    ret: int = SomeChildClass().some_method("42"). # 
    ret2: float = SomeChildClass().some_method("42")

My IDE complains about a type mismatch:

pycharm expected type float

This is happening because my IDE is still using the type hint from SomeClass.some_method.


Research

I think the solution might be to use generics, but I am not sure if there's a simpler way.

Python: how to override type hint on an instance attribute in a subclass?

Suggests maybe using instance variable annotations, but I am not sure how to do that for a return type.


Solution

  • Okay so I was able to play around and combine the answers from @AntonPomieshcheko and @KevinLanguasco to come up with the a solution where:

    This is exactly the behavior I had wanted. Thank you so much to everyone :)

    #!/usr/bin/env python3
    
    from typing import TypeVar, Generic, ClassVar, Callable
    
    
    T = TypeVar("T", float, int)  # types supported
    
    
    class SomeBaseClass(Generic[T]):
        """This base class's some_method will return a supported type."""
    
        RET_TYPE: ClassVar[Callable]
    
        def some_method(self, some_input: str) -> T:
            return self.RET_TYPE(some_input)
    
    
    class SomeChildClass1(SomeBaseClass[float]):
        """This child class's some_method will return a float."""
    
        RET_TYPE = float
    
    
    class SomeChildClass2(SomeBaseClass[int]):
        """This child class's some_method will return an int."""
    
        RET_TYPE = int
    
    
    class SomeChildClass3(SomeBaseClass[complex]):
        """This child class's some_method will return a complex."""
    
        RET_TYPE = complex
    
    
    if __name__ == "__main__":
        some_class_1_ret: float = SomeChildClass1().some_method("42")
        some_class_2_ret: int = SomeChildClass2().some_method("42")
    
        # PyCharm can infer this return is a complex.  However, running mypy on
        # this will report (this is desirable to me):
        # error: Value of type variable "T" of "SomeBaseClass" cannot be "complex"
        some_class_3_ret = SomeChildClass3().some_method("42")
    
        print(
            f"some_class_1_ret = {some_class_1_ret} of type {type(some_class_1_ret)}\n"
            f"some_class_2_ret = {some_class_2_ret} of type {type(some_class_2_ret)}\n"
            f"some_class_3_ret = {some_class_3_ret} of type {type(some_class_3_ret)}\n"
        )