list vs tuple vs deque vs array — which and why?

Pick by the operation you do most. list for ordered mutable data with random access; tuple when it must not change or must be a dict key; deque when you touch the front; array when you have millions of numbers; set when you only ask "is it in there?".

Overview

The three, in one table

 listtupledeque
MutableYesNoYes
HashableNoYes, if contents areNo
Append rightO(1) amortised—O(1)
Append leftO(n)—O(1)
Pop leftO(n)—O(1)
Index x[i]O(1)O(1)O(n)
SlicingYesYesNo
Memory per elementHigherLowerSimilar to list
Import neededNoNocollections

Two rows decide almost every real choice: deque is O(1) at both ends but O(n) to index, and tuple is hashable so it can be a dict key or a set member.

Lists & arraysConceptualEasy

Step through it

the five
list : ordered, mutable, O(1) index, O(n) at the front
tuple : ordered, immutable, hashable if its items are
deque : O(1) at BOTH ends, O(n) index
array : packed values, not pointers - far less memory
set : O(1) membership, no order, no duplicates
Five containers, five different trade-offs. The question is always which operation you do most.
choices5
Step 1 of 3

What to watch

  • The front of a list is the trap — O(n), where a deque is O(1).
  • Hashability is the real tuple/list distinction, not immutability for its own sake.
  • An array stores values; a list stores references to them.

Say this out loud

"Tuple if it's fixed or needs to be hashable - it can be a dict key, a list can't. deque if I'm touching the front, because list.pop(0) is O(n). array or numpy for large numeric data, since a list stores pointers rather than values."

list vs tuple vs deque vs array — which and why?

When would you use a tuple instead of a list? What about deque or array?

Run it

The five containers measured rather than described: the operation each is fast at, the memory each uses for the same thousand integers, and the two errors that pick the container for you.

When to use each

list is the default. Random access, sorting, slicing, appending at the end — all good. Only reject it when you need something it cannot do.

tuple when the sequence is a fixed record rather than a collection, or when it must be hashable:

The hashability is the hard requirement — a list simply cannot be a dict key. The immutability is also a signal to the reader that the contents are not going to change, which is why returning a tuple from a function that produces a fixed set of values is idiomatic.

deque when you add or remove at the front:

maxlen is the underrated feature. A bounded deque discards from the opposite end automatically, which gives you a rolling window or a fixed-size log buffer with no bookkeeping at all.

The performance trap that matters

list.pop(0) and list.insert(0, x) are O(n), because every remaining element shifts one position. Inside a loop, that makes the whole operation quadratic:

Roughly five billion element moves. Swapping in a deque makes it linear:

Any breadth-first search, task queue, or producer-consumer loop should use a deque. This is the single most common reason a straightforward-looking Python loop is slow, and it is invisible in small tests — a thousand elements finishes fine, and a hundred thousand does not.

The mirror-image mistake also exists: reaching for a deque and then indexing it in a loop. dq[i] walks the internal block list, so a positional loop over a deque is O(n²). Use a list when you index, a deque when you push and pop at the ends.

tuple versus list

The textbook answer is "tuples are immutable", which is true and not the point. The consequence is that a tuple is hashable (if its contents are), so it can be a dictionary key or a set member — which is why coordinates, database rows and cache keys are tuples.

The secondary signal is meaning. A list is a homogeneous sequence of unknown length; a tuple is a fixed-size record where position carries meaning. (x, y) is a point; [x, y] is two numbers.

deque versus list

collections.deque is a doubly linked list of blocks, so appendleft and popleft are O(1) where the list equivalents are O(n). Any queue, BFS frontier or "last N items" buffer should be a deque.

The trade is random access: d[5000] walks the blocks, so it is O(n). If you index into the middle, keep the list. A deque also takes maxlen, which turns it into a fixed-size ring buffer that discards the oldest entry automatically.

array and the memory question

A list holds references, so a list of a million integers is a million pointers plus a million integer objects. array.array packs the values inline in one typed block, which is several times smaller and much friendlier to the cache.

For real numeric work the answer is numpy, which adds vectorised operations on top of the same packed layout. Mentioning that a list of numbers is a list of pointers is usually the specific thing an interviewer is listening for.

Why tuples are smaller and faster

A list over-allocates so that append is amortised O(1), and it stores a capacity alongside its length. A tuple is fixed at creation, so it needs neither — less memory, one less indirection, and marginally faster iteration.

CPython also caches small tuples for reuse, and constant tuples are built at compile time:

So for x in (1, 2, 3) is very slightly faster than the list version. This is a real but tiny effect, and not a reason to choose a tuple — choose based on mutability and hashability, and take the memory win as a side benefit.

Immutability is shallow

A tuple's immutability applies to its own slots, not to what they point at:

The tuple guarantees its references will not change, and says nothing about the objects behind them. That is also why a tuple containing a list is unhashable: hashing recurses into the contents, so one mutable element makes the whole thing unhashable.

The practical rule: a tuple is only usable as a dict key if everything inside it is hashable too. Convert nested lists to tuples, and sets to frozenset.

The rest of the family

NeedUse
Fixed record with named fieldsNamedTuple or dataclass(frozen=True)
Queue between threadsqueue.Queue — deque plus locking
Priority queueheapq on a list
Array of numbers, compactarray.array or NumPy
Sorted insertionbisect.insort on a list
Immutable setfrozenset
Ring bufferdeque(maxlen=n)

NamedTuple is the natural upgrade once a tuple's positions acquire meaning. point.x beats point[0], it stays a tuple, and it costs no extra memory:

deque is thread-safe for append and popleft individually, because those are atomic at the C level. That does not make a check-then-pop sequence safe — use queue.Queue when several threads coordinate through it.

Questions people ask

Why is list.pop(0) slow? Every subsequent element shifts down one slot. Use deque.popleft.

Can I index a deque? Yes, and at O(n). Indexing in a loop is quadratic.

Why can a tuple not be a dict key sometimes? If it contains a mutable object, it is unhashable.

Is a tuple actually faster? Marginally, from less allocation and compile-time constants. Not a deciding factor.

What about slicing a deque? Unsupported. Use itertools.islice, or a list if slicing is central.

deque or queue.Queue for threads? Queue when threads coordinate; deque when a single owner mutates it.

Does tuple copying help? tuple(lst) snapshots the references — a shallow copy, so shared mutable elements are still shared.

Recap in one screen

  • list is the default; tuple when the sequence is a fixed record or must be hashable; deque when you touch both ends.
  • list.pop(0) and insert(0, x) are O(n) and turn ordinary loops quadratic — use deque for queues and BFS.
  • Indexing a deque is O(n), so do not loop over it positionally.
  • Tuple immutability is shallow: the slots are fixed, the objects inside may not be, and one mutable element makes it unhashable.
  • deque(maxlen=n) gives a rolling window for free; NamedTuple gives a tuple with named fields.

Check yourself

0 of …

Answer without scrolling back up.

  1. The most practical difference between a tuple and a list is that a tuple:

  2. You need a queue. Which container?

  3. array.array uses less memory than a list of the same integers because it:

Cheat sheet

list vs tuple vs deque vs array — which and why?

Pick by the operation you do most. list for ordered mutable data with random access; tuple when it must not change or must be a dict key; deque when you touch the front; array when you have millions of numbers; set when you only ask "is it in there?".

INTERVIEW · AI.Cruz.in/interview/list-versus-tuple-versus-deque.html

About the author

AI.Cruz builds and maintains AI.Cruz. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.