[Answered] Typehints for functions that have variable signatures
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
from typing import Union is probably what you're looking for, but yes, I'd argue you should try to avoid that kind of pattern, even if it's convenient.
Sorry for the triple(?) notifications. Trying out the beta version of the boost app and it's still a bit buggy.
Agreed. I avoid having the shape of the return type be determined by arguments. Having the return type be generic is one thing. But this is different as here you are taking about returning 1 object or 2 objects.
but from a practical perspective, let's say you retrieve an object and can either return a subset of its fields as your API.
Doesn't it make sense to re-use the same function, but change what fields are returned?
I'm specifically talking about the narrow use-case where your API returns either A or B of the fields, and won't extend it in the future
The alternative is to either duplicate the function, or extract it out which seems a bit overkill if it is only 2 different type of functions.
But I don't think such constructs are possible?
I know it is possible in Typescript to define the types using constants, but I don't suppose Python allows for this?
EDIT: At first, when I tried the above, the typechecker said Literal[True] was not expected and I thought it was not possible.
But after experimenting some, I figured out that it is actually possible.
Added my solution to the OP