How to store data in Python without regretting it later — the standard containers.
Fundamentals 13 min Beginner April 26, 2026
So far, every variable you have created holds exactly one value — a number, a string, a boolean. But real programs deal with collections: a list of 1,000 student names, a user profile with name, age, and city, or an API response with hundreds of data points. Managing 1,000 separate variables is like keeping 1,000 loose sticky notes instead of one organized notebook.
Python provides two fundamental collection types: lists for ordered sequences (when position matters) and dictionaries for key-value pairs (when you want to look things up by name). These two structures are so central that nearly every Python program uses at least one of them.
Lists — Ordered Collections with Numbered Slots
List (list)
AnalogyDefinition
A list is like a numbered shelf in a workshop. Each slot has a number starting from 0 — Slot 0, Slot 1, Slot 2. You can put any item in any slot, add new slots at the end (append), remove a slot and shift everything after it (pop), or insert a new slot in the middle (insert). To find something, you either know its slot number (index access) or scan all slots (the in operator).
Analogy:
A list is like a numbered shelf in a workshop. Each slot has a number starting from 0 — Slot 0, Slot 1, Slot 2. You can put any item in any slot, add new slots at the end (append), remove a slot and shift everything after it (pop), or insert a new slot in the middle (insert). To find something, you either know its slot number (index access) or scan all slots (the in operator).
Definition:
A Python list is an ordered, mutable sequence of elements. "Ordered" means the position of each element is preserved and meaningful — the first element stays first until you change the list. "Mutable" means you can add, remove, and replace elements in-place without creating a new list. Each element is accessed by its index, starting at 0. Lists can hold any mix of types: [42, "Anna", True, [1, 2]].
The shelf analogy fits well for numbered positions and shifting during insert/remove. It breaks because a real shelf has a fixed number of slots — Python lists grow dynamically. Also, shelf slots have physical size constraints, while Python lists can hold any object, including other lists.
Each step shows the list state after the operation. Notice: after pop(1), all elements to the right shift one position to the left.
Watch Out: IndexError
The index must be between 0 and len(list) - 1. Accessing beyond these bounds raises an IndexError. Because Python starts at 0, list[3] is the fourth element — not the third.
colors = ["red", "green", "blue"]
print(colors[3]) # IndexError: list index out of range
# Valid indices: 0, 1, 2
Dictionaries — Looking Things Up by Name
Dictionary (dict)
AnalogyDefinition
A dictionary is like a phone book. You don't look up "the 47th entry" — you look up a name (the key) to find the phone number (the value). The phone book guarantees each name appears only once (unique keys), and looking up a name is fast regardless of how thick the book is. If you search for a name that isn't listed, you get an error (KeyError) — or use .get(): "Do you have Max Mueller? If not, just say 'unknown'."
Analogy:
A dictionary is like a phone book. You don't look up "the 47th entry" — you look up a name (the key) to find the phone number (the value). The phone book guarantees each name appears only once (unique keys), and looking up a name is fast regardless of how thick the book is. If you search for a name that isn't listed, you get an error (KeyError) — or use .get(): "Do you have Max Mueller? If not, just say 'unknown'."
Definition:
A Python dictionary (dict) is a mutable collection that maps unique keys to values. Instead of accessing by position (like lists), you access by a meaningful key: person["name"] gives the value for key "name". Keys must be immutable (strings, numbers, tuples); values can be anything. Since Python 3.7, dictionaries preserve insertion order, but the key (not position) remains the primary access method.
The phone book analogy fits for key-based access and uniqueness. It breaks because a real phone book is alphabetically sorted — Python dicts use hash tables, not alphabetical order. Also, a phone book contains only name-number pairs, while Python dicts can map any immutable key to any value, including nested dicts and lists.
Example: Person Record
person = {"name": "Anna", "age": 28, "city": "Berlin"}
print(person["age"]) # 28
person["job"] = "Engineer" # adds new key-value pair
print(person.get("hobby", "unknown")) # "unknown" (no error)
for key, value in person.items():
print(f"{key}: {value}") # prints all pairs
The .get() call is the safe counterpart to person["hobby"], which would crash with KeyError. Use .get() whenever you're not sure a key exists.
List
Ordered sequence. Access by index (position). Use lists when order matters: shopping lists, step sequences, collections you iterate through.
Dictionary
Key-value mapping. Access by key (name). Use dicts when you want to look things up by name: user profiles, configurations, word counters.
Watch Out: KeyError
Accessing dict[key] with a non-existent key raises a KeyError. Use .get(key, default) instead for safe access.
person = {"name": "Anna"}
print(person["hobby"]) # KeyError: 'hobby'
print(person.get("hobby", "unknown")) # "unknown" (no error)
Aliasing — When Two Names Share One Object
Aliasing
AnalogyDefinition
Aliasing is like a shared online document. Imagine you and a colleague both have a link to the same Google Doc. If your colleague edits a paragraph, you see the change immediately — because you're both looking at the same document, not separate copies. Creating a copy with a.copy() is like clicking "Make a copy" in Google Docs — now each of you has your own independent version.
Analogy:
Aliasing is like a shared online document. Imagine you and a colleague both have a link to the same Google Doc. If your colleague edits a paragraph, you see the change immediately — because you're both looking at the same document, not separate copies. Creating a copy with a.copy() is like clicking "Make a copy" in Google Docs — now each of you has your own independent version.
Definition:
Because lists and dictionaries are mutable objects, assigning b = a does not copy the data — it creates a second name (alias) pointing to the same object in memory. After b = a, both refer to the same list. Changing b[0] also changes a[0] because there is only one list with two names. For an independent copy, use a.copy(), list(a), or a[:] for lists, and a.copy() or dict(a) for dicts. These create shallow copies — the outer container is new, but nested objects inside still share references.
The document analogy fits for "two links, one object." It breaks because in real life, sharing a document is a deliberate choice (you send a link), while aliasing in Python happens automatically and silently when you write b = a. Beginners don't realize they're "sharing" the object.
The Aliasing Trap Step by Step
1
a = [1, 2, 3] → List with three elements created
2
b = a → b is an alias, NOT a copy! Both point to the same list.
3
b.append(4) → The list is now [1, 2, 3, 4]
4
print(a) → [1, 2, 3, 4] — a changed too! Fix: b = a.copy()
Aliasing Is Silent and Automatic
b = a does NOT copy. It creates a second name for the same object. Always use .copy() for an independent copy. This applies to lists AND dictionaries.
# Alias (NOT copied):
b = a
b.append(4) # also changes a!
# Real copy:
b = a.copy()
b.append(4) # a stays unchanged
List Ordered sequence with numbered positions (starting at 0)
Dictionary Key-value mapping for fast lookups
IndexError Accessing a position beyond the list length
KeyError Accessing a key that doesn't exist in the dictionary
Interactive: Python Collection Types Compared
You now know lists and dictionaries. But Python has two more collection types: sets and tuples. Click on a row in the comparison matrix to see the properties and typical use cases of each type. Pay attention to the color coding: green indicates available capabilities, red indicates limitations.
Python Collection Types Compared
Advantage (small/fast/high)
Neutral
Disadvantage (large/slow/low)
Click a row for detail view
Type
Ordered
Mutable
Duplicates
Access
▸list
✓
✓
✓
Index [i]
▸dict
✓
✓
✗ Keys
Key ["k"]
▸set
✗
✓
✗
—
▸tuple
✓
✗
✓
Index [i]
Key Takeaway: Choosing the right collection type depends on three questions: Do you need a specific order? Should the collection be mutable? Must elements be unique? The matrix shows at a glance which type meets which requirements.
Deep Dive: Why Does Python Count from 0?
Guido van Rossum, Python's creator, explained the decision in a 2013 blog post: half-open intervals like a[:n] for the first n elements and a[n:] for the rest work cleanly with 0-based indices, without fiddly +1/-1 corrections. This design comes from the C tradition that heavily influenced Python.
A practical benefit: len(list) is always the first invalid index — making boundary checks easy.
Deep Dive: Lists, Dicts, and JSON
JSON (JavaScript Object Notation) is the standard format for web APIs, AI model configurations, and data exchange. When loaded with json.loads(), JSON objects become Python dicts and JSON arrays become Python lists.
Understanding lists and dictionaries means understanding the structure of real-world data — from API responses to configuration files.
Key Takeaways
A list is an ordered, mutable sequence accessed by index (starting at 0). Use lists when order matters — shopping lists, step sequences, collections you iterate through.
A dictionary is a mutable collection of key-value pairs accessed by key. Use dicts when you want to look things up by name — user profiles, configurations, word counters.
b = a does not copy a list or dictionary — it creates a second name for the same object. Use a.copy() or list(a) for an independent copy.
Common traps: IndexError (accessing beyond list length), KeyError (accessing a missing dict key — use .get()), off-by-one errors from 0-based indexing.
JSON — the format for web APIs and AI services — maps directly to Python dictionaries and lists. Understanding these two types means understanding the shape of real-world data.
Quiz: Lists and Dictionaries
Question 1 / 4
Not completed
What does colors[1] return if colors = ["red", "green", "blue"]?
1. What does colors[1] return if colors = ["red", "green", "blue"]?
☐ A) "red"
☐ B) "green"
☐ C) "blue"
☐ D) IndexError
2. person = {"name": "Anna", "age": 28}. What does person.get("hobby", "unknown") return?
☐ A) KeyError
☐ B) None
☐ C) "unknown"
☐ D) "hobby"
3. a = [1, 2, 3]; b = a; b.append(4). What is a now?
☐ A) [1, 2, 3]
☐ B) [1, 2, 3, 4]
☐ C) [4, 1, 2, 3]
☐ D) Error
4. You want to store 500 user profiles (each with name, email, age). Which structure fits best?
☐ A) 500 separate variables
☐ B) A list of 500 dictionaries
☐ C) A dictionary with 500 lists
☐ D) 3 separate lists (one for names, one for emails, one for ages)
Answer Key: 1) B · 2) C · 3) B · 4) B
Checkpoint: Do You Understand Lists and Dictionaries?
You have the list colors = ["red", "green", "blue"]. What does colors[1] return? And what happens with colors[5]?
You have person = {"name": "Anna"}. What's the difference between person["hobby"] and person.get("hobby", "unknown")?
You write b = a and then change b. Why does a change too? How do you prevent this?