this post was submitted on 23 Sep 2023
22 points (95.8% liked)

Python

6360 readers
9 users here now

Welcome to the Python community on the programming.dev Lemmy instance!

📅 Events

PastNovember 2023

October 2023

July 2023

August 2023

September 2023

🐍 Python project:
💓 Python Community:
✨ Python Ecosystem:
🌌 Fediverse
Communities
Projects
Feeds

founded 1 year ago
MODERATORS
 

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
you are viewing a single comment's thread
view the rest of the comments
[–] __init__@programming.dev 8 points 1 year ago (3 children)

You may be able to achieve this using typing.Overload with typing.Literal for your argument. Check out this post about overload: https://adamj.eu/tech/2021/05/29/python-type-hints-how-to-use-overload/

[–] eternacht@programming.dev 1 points 1 year ago

This is the real answer, overloads are meant for exactly this purpose.

It’ll be something like this:

from typing import Literal, overload

@overload
def foo() -> Data: …
@overload
def foo(return_more: Literal[True]) -> tuple[Data, Data]: …
def foo(return_more: bool = False) -> Data | tuple[Data, Data]
    ...
    if return_more:
        return data, more_data
   return data
load more comments (2 replies)