We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Interfaces with Protocols and ABCs step 23 of 26
Keep the Type at Each Tuple Position with TypeVarTuple
This exercise is optional. It covers TypeVarTuple, a feature that most
code does not need, so you can skip it on a first pass.
Some helpers build tuples of different lengths. pairs("ab", 3) returns
("ab", 3), and prepend(True, ("ab", 3)) returns (True, "ab", 3). The
starter types their results with object, as in tuple[object, ...], a
tuple of any length whose items are only known to be objects. So mypy loses
the type at each position. Submit the starter, and mypy rejects three[1].upper():
L18:14 [attr-defined]
"object" has no attribute "upper"
The code runs, because three[1] is a string at runtime. The tests pass,
and mypy is the check that fails.
A type parameter for a sequence of types
An ordinary type parameter such as T stands for one type. A
TypeVarTuple, written *Ts, stands for a sequence of types, in order:
def pairs[*Ts](*args: *Ts) -> tuple[*Ts]:
return args
If label is a str and count is an int, pairs(label, count) has
the type tuple[str, int]. With no arguments, Ts is empty and the result
is tuple[()]. You can put ordinary type parameters before or after it, so
tuple[T, *Ts] is a T followed by the types in Ts. One tuple type can
hold only one *Ts.
What to write
Give the three helpers these signatures, and keep solve as it is:
pairs[*Ts](*args: *Ts) -> tuple[*Ts]returns its arguments as a tuple, in order. With no arguments it returns().prepend[T, *Ts](head: T, rest: tuple[*Ts]) -> tuple[T, *Ts]returnsheadfollowed by the items ofrest.restmay be empty.ends[B, *Rest, C](shape: tuple[B, *Rest, C]) -> tuple[B, C]returns the first and last items. Its input has at least two items, and the middle part may be empty.
Return tuples, not lists, and do not change the arguments.
What the driver returns
solve(label, count, flag) builds these values. The last column is the
type mypy infers once your signatures are in place:
| Key | Value | Type |
|---|---|---|
two |
(label, count) |
tuple[str, int] |
three |
(flag, label, count) |
tuple[bool, str, int] |
four |
(count, flag, label, count) |
tuple[int, bool, str, int] |
tagged |
label.upper() |
str |
ends |
(count, count) |
tuple[int, int] |
tagged uses Python's own upper(), so "ß" becomes "SS".
Going further
TypeVarTuple arrived in Python 3.11 with
PEP 646, and the [*Ts] syntax in
Python 3.12. The main example in PEP 646 is the shape of an array, such as
Array[Height, Width]. A TypeVarTuple describes positional types only.
For keyword arguments, use Unpack with a TypedDict, as earlier in this
track.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.