Skip to content

Tuples & Named Tuples Interview Questions & Answers

15 questions Updated 2026-06-18 Share:

Python interview questions on tuples vs lists, packing and unpacking, single-element tuples, shallow immutability, namedtuples, and tuples as dict keys.

Read the in-depth guidePython Tuples and Named Tuples Explained — Immutability, Packing, and namedtuple(opens in new tab)
15 of 15

A list is mutable and variable-length — use it for a homogeneous, changing collection you add to, remove from, or reorder. A tuple is immutable and fixed — use it for a heterogeneous, fixed record whose shape won't change, like a coordinate or a database row.

scores = [90, 85, 70]   # changing collection -> list
scores.append(60)       # fine

point = (3, 4)          # fixed record -> tuple
point[0] = 9            # TypeError — tuples are immutable

Tuples are also slightly faster and more memory-efficient, and because they're hashable they can serve as dict keys or set members (a list can't). Rule of thumb: reach for a tuple when the data is a fixed bundle that shouldn't change, and a list when you need to mutate the collection.

Packing collects several values into one tuple — the parentheses are often optional. Unpacking spreads a tuple's items into separate names in one assignment, which is how you return and receive multiple values cleanly.

t = 1, 2, 3          # packing (parentheses optional)
a, b, c = t          # unpacking -> a=1, b=2, c=3
first, *rest = t     # extended unpacking -> first=1, rest=[2, 3]

one = (5)            # NOT a tuple — just int 5 in parentheses
one = (5,)           # a 1-element tuple — the trailing comma makes it

The key gotcha is the single-element tuple: it's the trailing comma, not the parentheses, that creates a tuple — (5) is just the integer 5, while (5,) is a one-tuple. When in doubt, the comma is what defines a tuple.

A tuple's immutability is shallow. You can't reassign or resize its slots, but each slot just holds a reference — and if that reference points to a mutable object (like a list), that object can still be changed in place.

t = (1, [2, 3])
t[1].append(4)     # allowed — mutating the list inside the tuple
print(t)           # (1, [2, 3, 4])

t[1] = [9]         # TypeError — can't reassign a tuple slot

A consequence interviewers love: a tuple that contains a list is not hashable, because hashability requires every element to be immutable too — so hash((1, [2])) raises TypeError. Bottom line: the tuple's structure is frozen, but the objects it points to may not be.

A namedtuple is an immutable tuple subclass with named fields — giving you readable, hashable, lightweight records that still behave like tuples (index access, unpacking, comparison). There are two ways to define one.

from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
p.x, p[0]        # 3, 3  — named AND index access
p.x = 9          # AttributeError — immutable

from typing import NamedTuple
class Point(NamedTuple):     # class syntax with type hints + defaults
    x: int
    y: int = 0

The collections form is concise; the typing.NamedTuple class form adds type annotations, defaults, and the ability to add methods. Use a namedtuple for small fixed records when you want clarity over a bare tuple; reach for a @dataclass when you need mutability or richer behavior.

Dict keys and set members must be hashable, which in practice means immutable with a stable hash for the object's lifetime. A tuple of immutable values is hashable, so it works as a key; a list is mutable and unhashable, so it doesn't.

grid = {}
grid[(0, 0)] = "origin"   # tuple key — works
grid[(1, 2)] = "point"

grid[[3, 4]] = "x"        # TypeError: unhashable type: 'list'

This makes tuples ideal for composite / multi-part keys — like (row, col) coordinates or (lat, lon) pairs. The one caveat: a tuple is only hashable if all its contents are too, so (1, [2]) still fails. Use an immutable tuple whenever you need a multi-value key.

No — it's the commas that make a tuple, not the parentheses. 1, 2, 3 is a tuple; the parens just group for clarity or precedence. That's why functions "return multiple values" — they return one tuple built by commas.

t = 1, 2, 3          # (1, 2, 3)
def f(): return 1, 2 # returns the tuple (1, 2)
x = (5)              # int 5 !  -> need (5,) for a 1-tuple

Rule of thumb: the comma creates the tuple; add parentheses for readability or when a bare comma would be ambiguous.

Yes, modestly. Tuples use less memory and construct slightly faster because they're fixed-size and immutable — CPython can even cache small tuple objects and store constant tuples directly in bytecode. For large hot-path data this adds up.

import sys
sys.getsizeof((1, 2, 3))     # smaller
sys.getsizeof([1, 2, 3])     # larger (over-allocates for growth)

Rule of thumb: use a tuple for fixed, read-only groups of values; the immutability buys safety and a small efficiency win.

Only two: count(x) and index(x). Tuples are immutable, so there's no append, sort, remove, etc. To "change" a tuple you build a new one (e.g. via concatenation or sorted(), which returns a list).

t = (1, 2, 2, 3)
t.count(2)           # 2
t.index(3)           # 3
sorted(t)            # [1, 2, 2, 3]  -> a new LIST, not a tuple

Rule of thumb: tuples are for fixed data; if you need mutation methods, you want a list.

It adds named field access (p.x) on top of normal tuple behavior, plus helpers: ._fields, ._asdict(), ._replace(...) (returns a new one), and ._make(iterable). It stays a real tuple — indexable, unpackable, and hashable.

from collections import namedtuple
Point = namedtuple("Point", "x y")
p = Point(1, 2)
p.x, p[0]            # 1, 1
p._replace(y=9)      # Point(x=1, y=9)  -> new tuple
p._asdict()          # {'x': 1, 'y': 2}

Rule of thumb: use a namedtuple for lightweight, immutable records when you want self-documenting field names without writing a class.

Use a namedtuple when you want an immutable, tuple-like record that's indexable/unpackable and memory-light. Use a dataclass when you need mutability, methods, defaults with logic, type-checked fields, or inheritance. frozen=True dataclasses overlap with namedtuples but aren't tuples.

from dataclasses import dataclass
@dataclass
class Point:
    x: int
    y: int
    def dist(self): return (self.x**2 + self.y**2) ** 0.5

Rule of thumb: namedtuple for simple immutable value records; dataclass when you need behavior, mutability, or richer typing.

a, b = b, a works because the right side is evaluated to a tuple first, then unpacked into the targets. No temporary variable is needed — Python builds (b, a) and assigns both names at once.

a, b = 1, 2
a, b = b, a          # a=2, b=1
x, y, z = z, x, y    # rotate three values

Rule of thumb: use tuple unpacking for swaps and multi-assignment; it's clearer and avoids a scratch variable.

A function's *args collects extra positional arguments into a tuple. Conversely, a tuple can be splatted back into positional arguments with *. This is the same packing/unpacking machinery tuples use everywhere.

def f(*args):
    print(type(args))     # <class 'tuple'>

nums = (1, 2, 3)
f(*nums)                  # unpack tuple -> f(1, 2, 3)

Rule of thumb: *args is always a tuple; use *tuple to feed its items as separate positional arguments.

+ and * produce new tuples (the originals are unchanged, since tuples are immutable). This means repeated concatenation in a loop is O(n²) — build a list and convert once if you're accumulating.

(1, 2) + (3,)            # (1, 2, 3)  new tuple
(0,) * 3                 # (0, 0, 0)
# avoid: t = (); for x in xs: t += (x,)   # quadratic

Rule of thumb: tuple +/* is fine for one-offs; accumulate in a list and convert to a tuple at the end.

Lexicographically, element by element: compare the first items, and only if equal move to the next. This makes tuples a natural multi-key sort key and lets you compare versions or coordinates directly.

(1, 2) < (1, 3)          # True  -> first equal, 2 < 3
(2, 0) < (1, 9)          # False -> 2 > 1 decides immediately
sorted(people, key=lambda p: (p.last, p.first))

Rule of thumb: return a tuple as a sort key to sort by multiple fields in priority order.

Because parentheses are just grouping; without a comma (5) is the integer 5. The trailing comma is what creates a one-element tuple. This trips people up with single-item tuples and function calls.

type((5))        # <class 'int'>
type((5,))       # <class 'tuple'>
type(5,)         # also a tuple -> (5,)

Rule of thumb: always add the trailing comma for single-element tuples; the comma — not the parens — is the tuple.

More ways to practice

The self-quiz is live. Join our channel for updates, new content & tech tips.

Join our WhatsApp Channel