Search code examples
pythonoverloadingmypypython-typing

Catch-all overload for in Python type annotations


The below code fails mypy with error: Overloaded function signatures 1 and 2 overlap with incompatible return types.

@overload
def test_overload(x: str) -> str: ...

@overload
def test_overload(x: object) -> int: ...

def test_overload(x) -> Union[str, int]:
    if isinstance(x, str):
        return x
    else:
        return 1

What I'm trying to express is: "This function takes an arbitrary Python object. If that object is a string, it returns a string. If it is any other type, it returns an integer. Note this particular example is contrived to represent the general case.

Is it possible to express this with overloads?


Solution

  • At the moment (Python 3.10, mypy 0.961) there is no way to express any object except one. But you could use ignoring type: ignore[misc] for excepted types. And they must precede the more general variant, because for @overload order is matter:

    from typing import overload, Union
    
    
    @overload
    def test_overload(x: str) -> str:  # type: ignore[misc]
        ...
    
    
    @overload
    def test_overload(x: object) -> int:
        ...
    
    
    def test_overload(x) -> Union[str, int]:
        if isinstance(x, str):
            return x
        else:
            return 1
    
    
    reveal_type(test_overload("string"))  # Revealed type is "builtins.str"
    reveal_type(test_overload(object()))  # Revealed type is "builtins.int"