We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Structural Typing and the Hard Parts step 12 of 24
TypeVarTuple: generics over an arbitrary number of types
A TypeVar abstracts over one type. A TypeVarTuple abstracts over an
arbitrary number of them. It is what makes tuple[str, int] expressible
as the return of a function whose arity is not known in advance — and, in
the world this site’s users live in, it is what makes shape-typed array
signatures like Array[Batch, *Shape, Channels] possible at all.
The rules
- At most one TypeVarTuple per parameter list.
-
It is always written unpacked:
*Ts, never a bareTs. -
It combines with fixed types on either side:
tuple[Batch, *Shape, Channels]. -
*args: *Tsgivesargsthe typetuple[*Ts]— the exact element types and the exact arity, nottuple[object, ...]. -
An unparameterised variadic class defaults to
*tuple[Any, ...].
What PEP 646 explicitly does not do
Two non-goals, stated in the PEP, that save days if you know them up front:
-
No shape arithmetic. You cannot express “the output has dimension
n + 1“ or “these two dimensions multiply”. Type parameters are not integers. - No `kwargs` pairing.** There is no variadic analogue for keyword arguments.
If you need either, the answer is a runtime check, not a cleverer annotation.
Your task
def pairs[*Ts](*args: *Ts) -> tuple[*Ts]
def prepend[T, *Ts](head: T, rest: tuple[*Ts]) -> tuple[T, *Ts]
def ends[B, *Rest, C](shape: tuple[B, *Rest, C]) -> tuple[B, C]
def solve(label: str, count: int, flag: bool) -> dict[str, object]
solve builds two = pairs(label, count), three = prepend(flag, two),
four = prepend(count, three), takes tagged = three[1].upper() and
first, last = ends(four), and returns
{"two", "three", "four", "tagged", "ends"}.
Where the type system does the work
three[1].upper() is the assertion. three is
tuple[bool, str, int], so element 1 is a str and .upper() resolves.
Annotate pairs as (*args: object) -> tuple[object, ...] — the
“reasonable” non-variadic version — and that line stops compiling, because
the arity and the per-position types have been thrown away.
ends is the other half: it shows a TypeVarTuple sandwiched between two
ordinary type parameters, with shape[0] and shape[-1] resolving to B
and C respectively.
Return shapes matter
The tests compare tuples as tuples. Returning a list where a tuple is expected fails, deliberately — in Python the container type is frequently the thing under test.
Stuck?
Python reference solution
Sign in to attempt this problem and reveal the reference solution.