I'm curious if there's a way to use parentheses for type hinting tuples, like writing `def f() -> (int, str): ...` instead of using `Tuple[int, str]`. I couldn't find a PEP addressing this, so I wonder what the arguments against proposing or implementing this change might be.
5 Answers
Who said it’s not possible? With `from __future__ import annotations`, you can indeed define functions with tuples pretty easily like this: `def sus() -> (int, int): return 69, 420`. Just keep in mind that it’s not exactly semantically meaningful in the type system, as it’s returning a tuple instance instead of a true tuple type.
It’s actually quite tricky to implement this without causing issues elsewhere. Jelle Zijlstra's post titled 'Why Can't We...?' dives into these challenges. For instance, using parentheses could conflict with subscript syntax (like `Foo[(A, B)]` which is interpreted the same as `Foo[A, B]`), and could confuse the type system around unions. Check out his article for a deeper look!
Thanks so much!
The main concern here is about consistency across all type hints. If we start using a syntax like (int, str) for tuples, it could lead to confusion when used in different contexts, like `list[dict[str,(int, str)]]`. The current `list[dict[str, tuple[int, str]]]` keeps things pretty straightforward. Plus, (int, str) is a valid tuple expression, which could create ambiguity in various cases, particularly with custom types that allow subscripting.
I get where you're coming from. The parser was updated in 3.10, but adding this would still take some time.
I think there's nothing wrong with having syntactic sugar for tuples, like in Rust. It could make type hinting feel cleaner.
You can already hint a tuple without needing any imports! It's straightforward as is.
Why not just use dataclasses if you're after heterogeneous typed tuples? They provide a clear structure and are easy to work with.

That's interesting! It seems like it’s possible syntactically, but the type meaning gets lost.