I know what I am asking is rather niche, but it has been bugging me for quite a while. Suppose I have the following function:

def foo(return_more: bool):
   ....
    if return_more:
        return data, more_data
   return data

You can imagine it is a function that may return more data if given a flag.

How should I typehint this function? When I use the function in both ways

data = foo(False)

data, more_data = foo(True)

either the first or the 2nd statement would say that the function cannot be assigned due to wrong size of return tuple.

Is having variable signature an anti-pattern? Is Python’s typehinting mechanism not powerful enough and thus I am forced to ignore this error?

Edit: Thanks for all the suggestions. I was enlightened by this suggestion about the existence of overload and this solution fit my requirements perfectly

from typing import overload, Literal

@overload
def foo(return_more: Literal[False]) -> Data: ...

@overload
def foo(return_more: Literal[True]) -> tuple[Data, OtherData]: ...

def foo(return_more: bool) -> Data | tuple[Data, OtherData]:
   ....
    if return_more:
        return data, more_data
   return data

a = foo(False)
a,b = foo(True)
a,b = foo(False) # correctly identified as illegal
  • @nikaro
    link
    4
    edit-2
    9 months ago

    Python >= 3.10 version:

    def foo(return_more: bool) -> DataType | tuple[DataType, MoreDataType]: ...
    

    But i would definitely avoid to do that if possible. I would maybe do something like this instead:

    def foo(return_more: bool) -> tuple[DataType, MoreDataType | None]:
        ...
        if return_more:
            return data, more_data
       return data, None
    

    Or if data is a dict, just update it with more_data:

    def foo(return_more: bool) -> dict[str, Any]:
        ...
        if return_more:
            return data.update(more_data)
       return data