Python Lists, Tuples, and Dictionaries: A Complete Guide (2026)
🐍 Python Cluster — 2 of 15 · Fundamentals

Python Lists, Tuples, and Dictionaries: A Complete Guide (2026)

Python lists, tuples, and dictionaries are where the mutability rules from the last article stop being theoretical. A shopping cart function does cart_backup = cart before running a risky operation, expecting an independent snapshot. It isn't one. Both names point to the exact same list, so "backing it up" changed nothing — modifying cart silently modifies cart_backup too, because they were never two separate lists to begin with. This guide covers lists, tuples, and dictionaries in full: indexing, slicing, methods, and the copying rules that actually prevent this bug.

by Khalid Hussain Published Aug 4, 2026 🕐 13 min read

Quick Answer: Lists, Tuples, and Dictionaries

▶ Direct Answer — Python Lists, Tuples, and Dictionaries

A list ([]) is an ordered, mutable collection — items can be added, removed, or changed after creation. A tuple (()) is ordered but immutable — fixed once created. A dictionary ({}) stores key-value pairs instead of positions, so values are looked up by name rather than index. Plain assignment between two list variables never copies the list — both names end up pointing to the same object, which is the single most common structural bug in this area.

3
core structures: list, tuple, dict — each a different tradeoff
Ordered+mutable, ordered+fixed, keyed
0
copies made by plain assignment between two list variables
Both names share one object
.copy()
the method that actually creates an independent list
Covered in full below

The Backup That Wasn't

A function needs to try a risky bulk update on a shopping cart, with a fallback to the original if anything goes wrong. The instinct is to "save a backup" first:

pythonTHE_BUG.PY
cart = ["shirt", "shoes"]
cart_backup = cart          # looks like a backup — it isn't one

cart.append("hat")
cart.remove("shirt")

print(cart_backup)  # ['shoes', 'hat'] — the "backup" changed too

Nothing errors. Nothing warns. cart_backup = cart doesn't create a second list — it creates a second name pointing at the exact same list object in memory. Every mutation through cart is visible through cart_backup, because as far as Python is concerned, there was only ever one list. This is a direct consequence of the mutability covered in the previous article — and the actual fix is covered in the copying section below.

Lists: The Mutable Workhorse

A list holds an ordered collection of items, and unlike a tuple, it can grow, shrink, and change after creation.

pythonLISTS.PY
fruits = ["apple", "banana", "cherry"]

fruits.append("date")        # add to the end
fruits.insert(0, "apricot")  # insert at a specific position
fruits.remove("banana")     # remove by value
fruits.sort()                    # sort in place, alphabetically

print(len(fruits))            # 4

A list can hold mixed types — [1, "two", 3.0, True] is completely valid — though in practice, data science code usually keeps a list's contents uniform, since that's what most operations downstream expect.

Indexing and Slicing

Individual items are accessed by position, starting at 0; slices pull out a sub-range without modifying the original.

pythonSLICING.PY
numbers = [10, 20, 30, 40, 50]

print(numbers[0])       # 10 — first item
print(numbers[-1])      # 50 — last item, negative indexing
print(numbers[1:3])     # [20, 30] — index 1 up to (not including) 3
print(numbers[:2])      # [10, 20] — from the start
print(numbers[::-1])    # reversed copy of the whole list

The slice's end index is always exclusive — numbers[1:3] stops before index 3, returning exactly two items. This trips up beginners coming from languages with inclusive ranges, and it's worth memorizing early since it's consistent across lists, tuples, and strings alike.

Tuples: Fixed and Hashable

A tuple looks like a list but can never be changed after creation — no append, no remove, no in-place sort.

pythonTUPLES.PY
coordinates = (40.7128, -74.0060)
rgb_red = (255, 0, 0)

# coordinates.append(1)  # AttributeError — tuples have no append

# unpacking works the same as with lists
lat, lon = coordinates

Because tuples are immutable, they're hashable — usable as dictionary keys or set members, which a list can never be. Reach for a tuple whenever a value is genuinely fixed by nature: coordinates, an RGB triple, or a function returning more than one value.

Dictionaries: Key-Value Pairs

A dictionary looks up values by name (a key) instead of by numeric position — the standard structure for labeled, structured data.

pythonDICTIONARIES.PY
customer = {
    "name": "Maria",
    "age": 28,
    "active": True
}

print(customer["name"])         # "Maria" — raises KeyError if missing
print(customer.get("email"))   # None — no error, key doesn't exist
print(customer.get("email", "n/a"))  # "n/a" — with a default

for key, value in customer.items():
    print(key, value)

dict[key] raises a KeyError the moment a key doesn't exist; .get() returns None (or a default you specify) instead, silently. Use square brackets when a missing key is genuinely a bug you want surfaced; use .get() when a missing key is a normal, expected case.

Copying Correctly: The Actual Fix

This is what resolves the hook at the top of this article — creating an independent copy instead of a second name for the same object.

pythonCOPYING.PY
cart = ["shirt", "shoes"]
cart_backup = cart.copy()   # a genuine, independent copy now

cart.append("hat")
cart.remove("shirt")

print(cart_backup)  # ['shirt', 'shoes'] — untouched, exactly as intended

.copy(), list(cart), and the slice cart[:] all create a genuine independent copy. None of these go deep, though — if the list contains other lists or dictionaries nested inside it, the inner objects are still shared between the original and the copy. For fully independent nested structures, copy.deepcopy() from the standard library is the correct tool.

Choosing the Right Structure

NeedStructureWhy
A collection that will grow or shrinklistMutable, ordered
A fixed set of values, or a dict keytupleImmutable, hashable
Values that need a name, not a positiondictKey-based lookup

Mistakes That Give Away a Beginner

  • Assuming assignment copies a list. The exact trap from this article's opening — it creates a second reference, not a second list.
  • Using square-bracket access when a key might be missing, causing an unhandled KeyError instead of using .get() deliberately.
  • Trying to use a list as a dictionary key and hitting a TypeError — lists aren't hashable; use a tuple instead.
  • Forgetting slice ends are exclusive, off-by-one errors on the last element of a slice.
  • Reaching for a shallow .copy() on nested data and being surprised the inner lists are still shared — deepcopy is needed for that.

Practice: Fix These Three Yourself

1

Fix the backup bug

Rewrite the shopping-cart example so cart_backup genuinely stays unchanged after cart is modified.

2

Build a lookup dictionary

Given a list of (name, score) tuples, build a dictionary mapping each name to its score.

3

Slice practice

Given a list of 10 numbers, return the first 3, the last 3, and the list reversed, using slicing only.

Frequently Asked Questions

What is the difference between a list and a tuple in Python?

A list is mutable, meaning items can be added, removed, or changed after creation, and uses square brackets. A tuple is immutable, meaning it cannot be changed after creation, and uses parentheses. Tuples are typically used for fixed collections of values, while lists are used when the collection needs to grow, shrink, or change.

Why did changing one list also change another list in Python?

This happens when two variables point to the same underlying list object rather than two separate copies. Writing new_list = old_list does not create a copy — it creates a second name pointing to the same list in memory, so a change through either name is visible through both. Use old_list.copy() or list(old_list) to create an independent copy.

Can a dictionary key be a list in Python?

No. Dictionary keys must be hashable, and lists are mutable, which makes them unhashable. Attempting to use a list as a dictionary key raises a TypeError. Tuples, which are immutable, can be used as dictionary keys instead.

How do you copy a list in Python without changing the original?

Use the .copy() method, the list() constructor, or a slice with [:], for example new_list = old_list.copy(). Any of these creates a new, independent list object, so changes to the copy do not affect the original. For nested lists containing other lists, a deep copy from the copy module may be needed instead.

When should I use a tuple instead of a list in Python?

Use a tuple when the collection of values is fixed and shouldn't change, such as coordinates, RGB color values, or a function returning multiple values. Tuples are also required when a fixed collection needs to be used as a dictionary key or stored in a set, since lists cannot be used in either case.

What is the difference between dict.get() and dict[] in Python?

Accessing a dictionary with square brackets, like my_dict['key'], raises a KeyError if the key doesn't exist. dict.get('key') returns None instead of raising an error, and optionally accepts a default value to return, such as dict.get('key', 0), making it the safer choice when a key might be missing.

Conclusion: Know What You're Actually Copying

Lists, tuples, and dictionaries cover almost every data-shape need in everyday Python: an ordered, changeable collection; a fixed, hashable one; or a labeled lookup. The habit worth carrying forward from this article is the one that fixes the opening bug — plain assignment between two variables never copies a mutable object, it just adds a second name to the same one. Reach for .copy(), list(), or deepcopy() the moment independence actually matters.

Practice the three exercises above, then move to the next article in this cluster, which covers control flow — if statements and loops — the logic that actually operates on these structures.

🐍 Continue the Python Cluster

Next Up: Python Control Flow

If statements, loops, and the logic that ties these data structures together.

▶  Read the Control Flow Guide