Which data structure should you use in Python? Start with a list for an ordered, changeable collection, a dict for lookup by key, a set for unique membership, a deque for queues or both-end operations, and heapq when the next item is chosen by priority. Use a tuple for a fixed record, frozenset for an immutable set, and array.array for homogeneous numeric values. A stack and a queue are access patterns implemented with those containers, not additional built-in container classes.
Python does not define an official list of exactly ten structures. The ten practical choices below combine built-in containers, standard-library types and two common access patterns. Examples run on current Python 3; the max-heap API mentioned later requires Python 3.14.
Quick comparison
| Choice | Best for | Mutable? | Duplicates | Typical access |
|---|---|---|---|---|
list |
General ordered collections and stacks | Yes | Allowed | Index or end |
tuple |
Fixed records and unpacking | No (top level) | Allowed | Index |
dict |
Key-to-value lookup | Yes | Keys unique; values may repeat | Hashable key |
set |
Unique membership and set algebra | Yes | Not allowed | Membership |
frozenset |
Hashable, immutable sets | No | Not allowed | Membership |
array.array |
Typed numeric sequences | Yes | Allowed | Index |
deque |
FIFO queues and both-end work | Yes | Allowed | Either end |
| Stack pattern | LIFO workflows | Depends on container | Depends on container | Last in, first out |
| Queue pattern | FIFO workflows | Depends on container | Depends on container | First in, first out |
heapq |
Repeatedly selecting the smallest priority | Heap list is mutable | Allowed | heap[0] then pop |
Choose based on the operation you perform most, not on the apparent shape of the data. Hash-based containers require hashable keys or elements; a mutable list, for example, cannot be a dictionary key.
1. List: the flexible ordered default
A list preserves order, allows duplicates and can be changed in place. It is the usual starting point when you need indexing, iteration, appending or removing items.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →#1 Best Overall
scores = [91, 84, 97]
scores.append(88)
scores[1] = 86
print(scores) # [91, 86, 97, 88]
print(scores[0]) # 91
Appending and popping at the right end are natural list operations. However, inserting or removing at index zero shifts the remaining elements, incurring O(n) movement. Do not use a list for a busy FIFO queue; use deque instead.
2. Tuple: an immutable sequence
A tuple is an immutable sequence, useful for a fixed record such as a coordinate or a function result containing different types.
point = (3, 5)
x, y = point
print(x, y)
one = (3,) # the comma creates a one-item tuple
not_a_tuple = (3) # this is just the integer 3
Immutability applies to the tuple’s references, not necessarily to objects inside it:
record = ("job-7", ["queued"])
record[1].append("started") # the nested list can change
A tuple is hashable only when all of its contents are hashable. A suitable tuple can therefore be a dictionary key or a set member; a tuple containing a list cannot.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minute3. Dictionary: map meaningful keys to values
A dict is a mutable mapping with unique, hashable keys. Use it when the question is “what value belongs to this name or identifier?” rather than “what is at position 4?” Insertion-order iteration is documented.
prices = {"tea": 3.5, "coffee": 4.0}
prices["tea"] = 3.75
print(prices.get("juice", 0)) # 0
for name, price in prices.items():
print(name, price)
Indexing a missing key raises KeyError. Use get() for a default, or test with in. Keys must be hashable, so a list cannot be used as one.
Rank #2
4. Set: unique values and set algebra
A set is mutable, unordered and contains no duplicate elements. It is useful for deduplication and fast membership tests, plus union, intersection and difference operations.
unique_tags = set(["python", "data", "python"])
print(unique_tags)
print("data" in unique_tags)
backend = {"api", "python", "sql"}
frontend = {"python", "javascript"}
print(backend & frontend) # intersection
print(backend | frontend) # union
print(backend - frontend) # difference
Use set() for an empty set; {} creates an empty dictionary. Never rely on a stable set iteration order.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
5. Frozenset: an immutable set
frozenset has set membership and algebra operations but cannot be changed. Because it is immutable and hashable when its elements are hashable, it can itself be a dictionary key or a member of another set.
permissions = frozenset({"read", "write"})
roles = {permissions: "editor"}
print(roles[permissions])
Choose it when the collection of members is part of a fixed value, such as a permission combination, rather than a work set that will be updated.
6. Array: compact, type-constrained values
The standard-library array.array stores values constrained by a type code instead of arbitrary mixed Python objects. It is a practical option for homogeneous numeric data when that representation fits your application; do not assume it is automatically faster or smaller for every workload.
from array import array
readings = array("i", [4, 8, 12])
readings.append(16)
print(readings.tolist()) # [4, 8, 12, 16]
The type code must match values you append. For tabular analysis or advanced numerical operations, specialized third-party libraries may be more appropriate, but array is available without an extra dependency.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →7. Deque: efficient operations at both ends
collections.deque (double-ended queue) supports appending and popping from either end with approximately O(1) performance. The Python documentation recommends it for queues because list operations at the front move the remaining entries.
from collections import deque
tasks = deque(["a", "b"])
tasks.append("c")
first = tasks.popleft()
tasks.appendleft("urgent")
last = tasks.pop()
print(first, last, tasks)
Deque indexing is fast at the ends and slows toward the middle, so use a list for frequent random access. A bounded deque discards entries from the opposite end when full:
recent = deque(maxlen=3)
for item in [1, 2, 3, 4]:
recent.append(item)
print(recent) # deque([2, 3, 4], maxlen=3)
8. Stack: a last-in, first-out pattern
A stack describes behavior, not a separate standard built-in type. A list is usually sufficient: append the newest item and pop from the same end.
stack = []
stack.append("page A")
stack.append("page B")
current = stack.pop()
print(current) # page B
This pattern suits undo histories, depth-first traversal and nested processing. Avoid mixing front removals into a list-based stack; it defeats the efficient end operation.
9. Queue: a first-in, first-out pattern
A queue removes entries in arrival order. Implement it with deque, not repeated list.pop(0). The Python Software Foundation’s tutorial states: “To implement a queue, use collections.deque which was designed to have fast appends and pops from both ends.”
from collections import deque
queue = deque(["first", "second"])
queue.append("third")
next_item = queue.popleft()
print(next_item) # first
The queue is the FIFO rule; deque is the concrete container. For thread-safe producer/consumer coordination with blocking operations, consider the standard-library queue module rather than treating a bare deque as a synchronization primitive.
10. Heap-based priority queue with heapq
Use heapq when the next item should be selected by priority instead of arrival time. It maintains a heap over an ordinary list; it does not keep the entire list sorted. The invariant guarantees that the smallest item is at index zero.
import heapq
jobs = [5, 1, 3]
heapq.heapify(jobs) # linear-time transformation
while jobs:
priority = heapq.heappop(jobs)
print(priority) # 1, then 3, then 5
For records, store a priority first:
jobs = []
heapq.heappush(jobs, (2, "send email"))
heapq.heappush(jobs, (1, "restart service"))
print(heapq.heappop(jobs)) # (1, 'restart service')
Python 3.14 adds documented max-heap functions such as heapify_max and heappop_max. On earlier versions, a common approach is to negate numeric priorities or store a comparable wrapper.
How to choose among them
Choose by ordering requirement
- Need sequence position and random indexing:
list,tupleorarray. - Need lookup by a meaningful key:
dict. - Need unique membership or set operations:
setorfrozenset. - Need both-end operations or FIFO:
deque. - Need the next smallest priority:
heapq.
Choose by mutability and duplicates
Lists, dictionaries, sets, arrays and deques can change. Tuples and frozensets cannot change at the top level. Lists, tuples, arrays and deques preserve duplicates; sets reject them, while dictionary keys are unique and values may repeat.
Remember the cost traps
- Repeated front insertion or removal on a list is O(n); use a deque.
- Deque end operations are approximately O(1), but middle indexing is not its strength.
heapq.heapify()transforms an existing list in linear time; each pop then returns the current minimum.- Hash-based containers require hashable keys or elements.
Troubleshooting common mistakes
“My empty set became a dictionary”
Use set(), not {}. Curly braces with no entries create a dictionary.
“The queue is slow”
If the code calls pop(0) on a list, replace the container with deque and call popleft().
“A tuple changed unexpectedly”
Inspect nested objects. The tuple reference is fixed, but a list or dictionary stored inside it remains mutable.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteBest Value
“Dictionary or set insertion fails”
The key or element is unhashable. Convert a mutable list to a tuple when its contents are suitable, or use a different representation.
“The heap is not sorted when printed”
That is expected. A heap only guarantees the smallest item at index zero. Repeatedly call heappop() to consume values in priority order.
Further reading
The official Python data-structures tutorial, data-type index, collections documentation and heapq documentation provide version-specific details. For a broader textbook treatment, Wiley lists Data Structures and Algorithms in Python by Michael T. Goodrich, Roberto Tamassia and Michael H. Goldwasser as a 768-page first-edition hardcover (ISBN 978-1-118-29027-9) at Wiley.
Or skip the browser setup
If your Python project also needs website screenshots for documentation or tests, ScreenshotNeo provides a single HTTP call instead of maintaining browser automation. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
Recommended Free Tools
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
See the ScreenshotNeo API documentation for all options. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Are stack and queue separate Python data types?
No. They describe LIFO and FIFO access rules. A list commonly implements a stack, while collections.deque commonly implements a queue.
Can a tuple be a dictionary key?
Yes, provided every object inside the tuple is hashable. A tuple containing a list is not hashable.
Does heapq sort a list?
No. It maintains a heap invariant with the smallest item at index zero; use repeated heappop calls for priority order.
Free tools Windows power users keep installed
One-click scans. No signup required.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

