Python Tuple Type Hints: tuple[int, str], …, and NamedTuple

A Python tuple type hint lists the type of each position in square brackets, so tuple[str, int] means exactly two items: a string, then an integer. Write tuple[int, ...] when the length can vary:

order: tuple[str, int, float] = ("Coffee Mug", 2, 12.50)
prices: tuple[float, ...] = (19.99, 5.25)

I tested everything with Python 3.12.5 and mypy 2.4.0 in Command Prompt, using made-up US orders and customers.

In this tutorial, we’ll annotate fixed and variable-length tuples, type an empty tuple, use NamedTuple, handle a tuple that may be None, and let mypy catch the mistakes.

Annotate a fixed-length tuple and check it with mypy

Python doesn’t enforce hints at runtime; a type checker like mypy reads them. Below, I run python file.py first and mypy file.py second. Here, the second call passes the quantity as the string "3":

def order_line(order: tuple[str, int, float]) -> str:
    item, qty, price = order
    return f"{qty} x {item} = ${qty * price:.2f}"


print(order_line(("Coffee Mug", 2, 12.50)))
print(order_line(("Notebook", "3", 4.25)))

Output:

2 x Coffee Mug = $25.00
Traceback (most recent call last):
  File "C:\pyguides\orders.py", line 7, in <module>
    print(order_line(("Notebook", "3", 4.25)))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\pyguides\orders.py", line 3, in order_line
    return f"{qty} x {item} = ${qty * price:.2f}"
                                ~~~~^~~~~~~
TypeError: can't multiply sequence by non-int of type 'float'
orders.py:7: error: Argument 1 to "order_line" has incompatible type "tuple[str, str, float]"; expected "tuple[str, int, float]"  [arg-type]
Found 1 error in 1 file (checked 1 source file)
Command Prompt output of mypy reporting an incompatible tuple type and Python raising a TypeError for the same call
Python doesn’t fail until it reaches the bad multiplication; mypy flags line 7 without running anything.

The same tuple[...] syntax works as a return type, which is handy when you return a tuple from a Python function.

Type a variable-length tuple and an empty tuple

Add ... after one type for a tuple of any length, including zero. For a tuple that must stay empty, use tuple[()]:

def cart_total(prices: tuple[float, ...]) -> float:
    return round(sum(prices), 2)


no_items: tuple[()] = ()
print(cart_total((19.99, 5.25, 3.50)))
print(cart_total(no_items))

point: tuple[int, int] = (3, 4, 5)

Output:

28.74
0
sizes.py:9: error: Incompatible types in assignment (expression has type "tuple[int, int, int]", variable has type "tuple[int, int]")  [assignment]
Found 1 error in 1 file (checked 1 source file)
Command Prompt output of a tuple[float, ...] function and mypy rejecting three items for tuple[int, int]
The sums print normally, and mypy rejects the three-item tuple assigned to tuple[int, int].

Variable-length hints fit tuples you pass to a function as arguments. With *args: float, you annotate the item type, not the tuple.

Use NamedTuple for tuples with field names

When positions are hard to remember, a NamedTuple class names each field, and it’s still a tuple:

from typing import NamedTuple


class Order(NamedTuple):
    item: str
    qty: int
    price: float = 0.0


lamp = Order("Desk Lamp", 1, 39.99)
print(lamp)
print(lamp.item, lamp.qty * lamp.price)

chair = Order("Office Chair", "2", 149.00)
print(chair.qty * 2)

Output:

Order(item='Desk Lamp', qty=1, price=39.99)
Desk Lamp 39.99
22
orders_nt.py:14: error: Argument 2 to "Order" has incompatible type "str"; expected "int"  [arg-type]
Found 1 error in 1 file (checked 1 source file)
Command Prompt output of a typed NamedTuple printing 22 for a string quantity and mypy reporting the arg-type error
Python happily prints 22 (string repetition), while mypy points at the string passed for qty.

That silent 22 is the bug hints prevent. Need mutable fields? Compare Python dataclass vs namedtuple, and see dataclass default values and type hints for the dataclass side.

How do you type a tuple that might be None?

Use a union with | (Python 3.10+) or Optional[tuple[str, str]]. mypy won’t let you unpack it until you check for None:

def find_customer(customer_id: int) -> tuple[str, str] | None:
    customers = {101: ("Emily Carter", "Austin, TX"), 102: ("James Miller", "Denver, CO")}
    return customers.get(customer_id)


name, city = find_customer(101)

Output:

customers.py:6: error: "None" object is not iterable  [misc]
Found 1 error in 1 file (checked 1 source file)
Command Prompt output of mypy reporting that None is not iterable when unpacking an optional tuple
mypy catches the unpacking because find_customer() can return None.

An is None check narrows the type, and mypy is happy:

def find_customer(customer_id: int) -> tuple[str, str] | None:
    customers = {101: ("Emily Carter", "Austin, TX"), 102: ("James Miller", "Denver, CO")}
    return customers.get(customer_id)


for cid in (101, 103):
    result = find_customer(cid)
    if result is None:
        print(cid, "not found")
    else:
        name, city = result
        print(cid, name, "-", city)

Output:

101 Emily Carter - Austin, TX
103 not found
Success: no issues found in 1 source file

Helpers like this are easier to debug when you can get the name of a function in Python in your log lines.

typing.Tuple vs the built-in tuple

Since Python 3.9, the built-in tuple accepts brackets, so typing.Tuple is a deprecated alias you’ll only need on 3.8 and older. Ruff flags it:

from typing import Tuple


def bounds(values: list[int]) -> Tuple[int, int]:
    return min(values), max(values)

Output:

legacy.py:1:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead
legacy.py:4:34: UP006 [*] Use `tuple` instead of `Tuple` for type annotation
Found 2 errors.
[*] 1 fixable with `--fix`.

A typed stub can hold just pass in a Python function while you sketch signatures.

Want to keep going with tuples and type hints? These are next:

Frequently asked questions

How do I type hint a tuple in Python?

List each position’s type: tuple[str, int]. Use tuple[int, ...] for any length.

What’s the difference between Tuple and tuple?

typing.Tuple is the old alias. On Python 3.9 and later, use the built-in tuple.

How do I type an empty tuple?

Use tuple[()]. tuple[int, ...] also accepts an empty tuple.

Does Python check tuple type hints at runtime?

No. Hints are stored in __annotations__ only. Run mypy or pyright to check them.

Should I use NamedTuple or a plain tuple hint?

Use NamedTuple when fields need names; a plain hint is fine for short pairs like coordinates.

Where are tuple annotations documented?

See Annotating tuples in the typing module docs.