Python Data Structures Explained With Examples
Learn when to use Python lists, tuples, sets, dictionaries, and queues with clear examples, selection rules, pitfalls, and runnable code.
Python’s built-in data structures let you store, organize, and retrieve values. The main choices are list, tuple, set, dict, and, for queue workflows, collections.deque.
Choose based on five questions:
- Does order matter?
- Will the collection change after creation?
- Are duplicate values allowed?
- Do you retrieve by position, membership, or a meaningful key?
- Do you need first-in, first-out processing?
| Structure | Mental model | Use it when | Watch for |
|---|---|---|---|
list |
Mutable ordered sequence | Items need order, indexing, slicing, or updates | Front insertion/removal is inefficient for queues |
tuple |
Fixed sequence of grouped values | A group’s slots should not be reassigned | It may still contain mutable objects |
set |
Unordered unique elements | Deduplication, membership, and set algebra | Do not rely on display order |
dict |
Unique keys mapped to values | Lookup by a meaningful key | Keys must be hashable |
collections.deque |
Double-ended queue | FIFO or fast operations at both ends | It is a standard-library type, not a literal |
1. Lists: ordered, mutable sequences
A list keeps items in sequence order and can be changed in place. You can index, slice, append, remove, sort, and iterate over it.
scores = [8, 10, 9]
scores.append(7)
print(scores) # [8, 10, 9, 7]
print(scores[0]) # 8
print(scores[1:3]) # [10, 9]
scores[0] = 11
last = scores.pop()
print(last) # 7
print(scores) # [11, 10, 9]
List comprehensions
A comprehension creates a list from an iterable, optionally filtering values.
numbers = [1, 2, 3, 4, 5]
squares = [n * n for n in numbers]
even_squares = [n * n for n in numbers if n % 2 == 0]
print(squares) # [1, 4, 9, 16, 25]
print(even_squares) # [4, 16]
Common list mistakes
append(value)adds one item;extend(iterable)adds each item from an iterable.remove(value)removes the first matching value and raisesValueErrorif none exists.- Indexing outside the list raises
IndexError. - Copy a list with
items.copy()oritems[:]when you need a separate outer list.
2. Tuples: fixed-position groups
A tuple is a sequence whose individual slots cannot be reassigned. Tuples are useful for records or values that belong together, such as coordinates.
point = (3, 5)
x, y = point
print(x, y) # 3 5
# Packing
color = 255, 128, 0
# Unpacking with a starred target
first, *middle, last = (1, 2, 3, 4)
print(first, middle, last) # 1 [2, 3] 4
The immutability applies to the tuple’s slots. A tuple can contain a mutable object, so the object inside may still change.
record = ("job-7", ["queued"])
record[1].append("started")
print(record) # ('job-7', ['queued', 'started'])
# This reassignment is invalid:
# record[0] = "job-8" # TypeError
Use a one-item tuple with a trailing comma: single = ("value",). Parentheses alone do not create the tuple.
3. Sets: unique values and membership
A set contains unique elements and is unordered. It is a good fit for removing duplicates, checking membership, and comparing groups.
seen = {"red", "blue", "red"}
print(seen) # {'red', 'blue'} in some order
print("blue" in seen) # True
seen.add("green")
seen.discard("red")
left = {"a", "b", "c"}
right = {"b", "c", "d"}
print(left | right) # union
print(left & right) # intersection
print(left - right) # difference
print(left ^ right) # symmetric difference
Set iteration order is not a contract for presentation. Sort values when deterministic output matters: for item in sorted(seen): ....
Create an empty set with set(). The literal {} creates an empty dictionary.
Set elements must be hashable. Strings, numbers, and tuples containing hashable values can be elements; a list cannot.
4. Dictionaries: key-value lookup
A dictionary maps unique keys to values. Retrieve a value by its key instead of a numeric sequence position.
prices = {"tea": 3, "coffee": 4}
print(prices["tea"]) # 3
prices["cocoa"] = 5
prices["tea"] = 4
if "coffee" in prices:
print(prices["coffee"])
removed = prices.pop("cocoa")
print(removed) # 5
print(list(prices.keys()))
summary = {name: price * 2 for name, price in prices.items()}
print(summary)
Safe lookup and iteration
Indexing a missing key raises KeyError. Use get when a default is appropriate.
stock = {"pens": 12}
print(stock.get("paper", 0)) # 0
for name, count in stock.items():
print(name, count)
Dictionary keys must be hashable. A list cannot be a key because it can change; a tuple of hashable values can be used.
5. Queues with collections.deque
A FIFO queue returns the item that arrived first. A list can model a queue, but removing from the front shifts the remaining elements and is slow for queue behavior. The Python tutorial recommends collections.deque for fast appends and pops at both ends.
from collections import deque
queue = deque(["first", "second"])
queue.append("third")
print(queue.popleft()) # first
print(queue) # deque(['second', 'third'])
queue.appendleft("urgent")
print(queue.pop()) # third
Use deque(maxlen=...) for a bounded rolling buffer. Calling popleft on an empty deque raises IndexError; check truthiness first or handle the exception.
6. How to choose the right structure
| Requirement | Choice | Reason |
|---|---|---|
| Keep order and edit items | list |
Mutable sequence with indexing and slicing |
| Group fixed-position values | tuple |
Slots cannot be reassigned |
| Remove duplicates | set |
Elements are unique |
| Test membership repeatedly | set |
Expresses membership directly |
| Look up by identifier | dict |
Maps a key to a value |
| Process arrivals FIFO | deque |
Designed for both-end operations |
| Preserve input order while deduplicating | dict.fromkeys(values) |
Dictionary keys are unique while retaining insertion order |
values = ["a", "b", "a", "c"]
unique_in_input_order = list(dict.fromkeys(values))
print(unique_in_input_order) # ['a', 'b', 'c']
7. Combining structures in real programs
Nested structures model records and collections of records.
orders = [
{"id": 101, "items": ("book", "pen"), "paid": True},
{"id": 102, "items": ("notebook",), "paid": False},
]
paid_ids = [order["id"] for order in orders if order["paid"]]
all_items = {item for order in orders for item in order["items"]}
print(paid_ids) # [101]
print(all_items) # unique items, unordered
Choose each layer for its job: a list for ordered records, a dictionary for named fields, a tuple for fixed item groups, and a set for unique aggregation.
8. Troubleshooting common errors
| Error or symptom | Cause | Fix |
|---|---|---|
IndexError: list index out of range |
The index is outside the sequence | Check len(items), valid indexes, or iterate directly |
KeyError |
A dictionary key is absent | Use key in mapping, get, or handle the exception |
TypeError: unhashable type: 'list' |
A mutable list was used as a set element or dictionary key | Use an immutable representation such as a tuple |
| Set output changes order | Sets are unordered | Use sorted(set_value) for display |
| Tuple assignment fails | Tuple slots cannot be reassigned | Create a new tuple, or use a list when fields must change |
| Queue processing becomes slow | Removing from the front of a list shifts elements | Use collections.deque and popleft |
| Changing a list while iterating skips items | Indexes move as elements are removed | Build a filtered list or iterate over a copy |
9. Performance, reliability, and cost considerations
These structures are primarily a correctness and clarity choice. The official tutorial specifically warns that front removal from a list is inefficient for queues and recommends deque. Avoid claiming a universal fastest structure without measuring your own workload.
- Use the structure that states your intent clearly.
- Keep keys and values consistent so lookups are predictable.
- Do not depend on set ordering for serialized output or user interfaces.
- For large data, consider memory usage and whether streaming iteration is better than building a list.
- When behavior matters, write small tests for empty collections, missing keys, duplicate inputs, and nested mutable values.
10. A runnable practice script
from collections import deque
def main():
scores = [8, 10, 9]
scores.append(7)
point = (3, 5)
x, y = point
tags = {"python", "data", "python"}
prices = {"tea": 3, "coffee": 4}
prices["cocoa"] = 5
queue = deque(["first", "second"])
queue.append("third")
print("scores:", scores)
print("point:", x, y)
print("tags:", sorted(tags))
print("tea price:", prices["tea"])
print("next job:", queue.popleft())
if __name__ == "__main__":
main()
11. Or skip the browser setup
If your Python application needs screenshots of documentation, reports, or data pages, ScreenshotNeo provides a website screenshot API and MCP server. You can keep learning Python data structures without installing or managing a browser.
One GET request returns a PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for all options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://docs.python.org/3/tutorial/datastructures.html \
-o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://docs.python.org/3/tutorial/datastructures.html",
},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://docs.python.org/3/tutorial/datastructures.html'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
const fs = require('node:fs');
fs.writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.
Create your free ScreenshotNeo account.
12. FAQ
What are data structures in Python?
They are ways to organize values so your program can store, retrieve, update, and process data. Lists, tuples, sets, dictionaries, and deques cover many everyday cases.
Should I use a list or tuple?
Use a list when the sequence must change. Use a tuple when the group’s positions should remain fixed.
When is a set better than a list?
Use a set when uniqueness or membership is the main requirement and element order does not matter.
Can a dictionary key be a list?
No. Keys must be hashable; use an immutable alternative such as a tuple when its contents are hashable.
Is a deque a built-in literal?
No. Import it from collections; it is part of Python’s standard library.
For the canonical behavior and additional examples, read the Python Data Structures tutorial.


