Lesson 6 of 16 · Level 2: Intermediate
Python Lists, Tuples, Dictionaries and Sets
- ⏱ 13 min read
- ❓ 4 review questions
- ✍️ Exercise with solution
In this lesson
- Work with lists and their most useful methods.
- Use tuples and unpacking.
- Store named data in dictionaries.
- Choose the right structure for the job, including sets.
- Build a corner store's inventory as a list of dictionaries and calculate what it's worth.
So far each variable has held a single value. In real life you work with collections: a customer list, the items in an order, a class roster. Python has four built-in data structures for that: lists, tuples, dictionaries and sets. Picking the right one makes your code simpler and faster, and it's one of the first things interviewers check in a junior Python developer.
Lists: ordered and changeable
products = ["keyboard", "mouse", "monitor"]
prices = [25.0, 12.5, 180.0]
mixed = ["Jane", 29, True] # types can be mixed, though it's unusual
empty = []
Reading and changing items
print(products[0]) # keyboard
print(products[-1]) # monitor
print(products[0:2]) # ['keyboard', 'mouse']
products[1] = "wireless mouse"
print(len(products)) # 3
print("monitor" in products) # True
Indexes and slices work exactly like they did with strings in lesson 3. The big difference: you can change a list in place, which you can't do with a string.
The methods you'll use most
| Method | What it does |
|---|---|
items.append(x) | Adds x to the end |
items.insert(i, x) | Inserts x at position i |
items.remove(x) | Removes the first occurrence of x |
items.pop() / items.pop(i) | Removes and returns the last item / the item at position i |
items.sort() | Sorts the list in place |
sorted(items) | Returns a sorted copy (the original stays as it was) |
items.reverse() | Reverses the order |
items.count(x) / items.index(x) | How many times x appears / where it is |
scores = [78, 92, 65, 88]
scores.append(95)
scores.sort(reverse=True)
print(scores) # [95, 92, 88, 78, 65]
print(sum(scores) / len(scores)) # 83.6
b = a doesn't create a copy: a and b are the same list with two names, so changing one changes the other. To copy, use b = a.copy() or b = list(a).
1. With fruits = ["pear", "grape"], what does the list look like after fruits.append("kiwi")?
append adds the item to the end. Lists are changeable (mutable); tuples aren't.
Tuples: lists that don't change
A tuple is like a list, but immutable: once created, it can't be modified. You write it with parentheses:
coordinates = (41.8781, -87.6298) # downtown Chicago
date = (2026, 10, 31)
latitude, longitude = coordinates # unpacking
print(latitude) # 41.8781
Use tuples for values that belong together and shouldn't change (coordinates, dates, fixed records), and as dictionary keys. Unpacking, assigning a tuple's values to several variables at once, is something you'll see everywhere, including in the for day, sale in zip(...) loop from lesson 5.
Dictionaries: named data
A dictionary stores key: value pairs. Instead of reaching an item by position, you reach it by name. It's the most useful structure for representing real-world "things":
customer = {
"name": "Jane Doe",
"email": "jane@mail.com",
"city": "Phoenix",
"purchases": 12,
}
print(customer["name"]) # Jane Doe
customer["purchases"] += 1 # update a value
customer["phone"] = "602-555-0147" # add a new key
del customer["city"] # delete a key
Safe access with get()
print(customer["address"]) # KeyError: the key doesn't exist
print(customer.get("address")) # None
print(customer.get("address", "—")) # — (a default value)
Looping over a dictionary
stock = {"keyboard": 15, "mouse": 40, "monitor": 3}
for product, quantity in stock.items():
alert = " ⚠ reorder" if quantity < 5 else ""
print(f"{product:10} {quantity:3}{alert}")
keyboard 15
mouse 40
monitor 3 ⚠ reorder
There are also .keys() (keys only) and .values() (values only): sum(stock.values()) gives you the total units, 58.
Counting with a dictionary
A classic use: counting how many times each item appears.
sales = ["mouse", "keyboard", "mouse", "monitor", "mouse"]
counts = {}
for product in sales:
counts[product] = counts.get(product, 0) + 1
print(counts) # {'mouse': 3, 'keyboard': 1, 'monitor': 1}
The trick is counts.get(product, 0): the first time a product shows up there's no key yet, so get returns 0 instead of crashing.
2. With prices = {"coffee": 12}, what does prices.get("tea", 0) return?
.get() returns the default value when the key doesn't exist; prices["tea"] would raise a KeyError.
Lists of dictionaries: your first "database"
Combine the two structures and you can represent a table, like a spreadsheet: each dictionary is a row and each key is a column.
orders = [
{"id": 1, "customer": "Jane", "total": 120.0, "paid": True},
{"id": 2, "customer": "Mike", "total": 85.5, "paid": False},
{"id": 3, "customer": "Jane", "total": 240.0, "paid": True},
]
unpaid = [o for o in orders if not o["paid"]]
jane_total = sum(o["total"] for o in orders if o["customer"] == "Jane")
biggest = max(orders, key=lambda o: o["total"])
print(len(unpaid)) # 1
print(jane_total) # 360.0
print(biggest["id"]) # 3
This is essentially how data arrives from an API or a JSON file, as you'll see in lessons 8 and 12. The key=lambda o: o["total"] argument tells max() (and sorted()) which field to compare.
Sets: unique items
emails = ["a@x.com", "b@x.com", "a@x.com"]
unique = set(emails)
print(len(unique)) # 2
team_a = {"Jane", "Mike", "Eva"}
team_b = {"Eva", "Carlos"}
print(team_a & team_b) # {'Eva'} (intersection)
print(team_a | team_b) # all 4 names (union)
print(team_a - team_b) # {'Jane', 'Mike'} (difference)
Sets have no order and no duplicates. They're ideal for removing repeats from an email list and for checking membership very quickly. Because they have no order, the names may print in a different order on your computer.
3. What does len(set([1, 2, 2, 3, 3, 3])) return?
A set keeps only unique items: {1, 2, 3}.
Which one should you use?
[]Ordered and changeable- Access
- By position:
products[0] - Use it for
- A sequence you'll modify: today's orders, test scores, prices.
()Ordered and immutable- Access
- By position or unpacking:
lat, lon = coordinates - Use it for
- A fixed group of values that shouldn't change: dates, coordinates.
{key: value}Named pairs- Access
- By key:
customer["email"]or.get() - Use it for
- Looking things up by name or ID: customer records, stock by product.
set()No order, no duplicates- Access
- You only ask if it's there:
"Eva" in team - Use it for
- Unique values and set math: deduplicated emails, customers in common.
Real case: a corner store's inventory
Fishtown Corner Market in Philadelphia wants to know how much cash is tied up in inventory by category and which products need reordering. Each product is a dictionary; the full inventory is a list. This example uses all four structures from the lesson:
# Inventory at Fishtown Corner Market (Philadelphia) - wholesale cost in USD
inventory = [
{"product": "Rice 5 lb", "category": "Pantry", "stock": 40, "cost": 3.10},
{"product": "Peanut butter 16 oz", "category": "Pantry", "stock": 6, "cost": 2.45},
{"product": "Milk 1 gal", "category": "Dairy", "stock": 30, "cost": 2.60},
{"product": "Cheddar 8 oz", "category": "Dairy", "stock": 4, "cost": 2.20},
{"product": "Detergent 92 oz", "category": "Cleaning", "stock": 18, "cost": 8.40},
{"product": "Soda 2 L", "category": "Beverages", "stock": 25, "cost": 1.35},
]
MIN_STOCK = 8
value_by_category = {}
for item in inventory:
value = item["stock"] * item["cost"]
cat = item["category"]
value_by_category[cat] = value_by_category.get(cat, 0) + value
to_reorder = [i["product"] for i in inventory if i["stock"] < MIN_STOCK]
categories = {i["category"] for i in inventory} # set: no duplicates
ranking = sorted(value_by_category.items(), key=lambda pair: pair[1], reverse=True)
for cat, value in ranking:
print(f"{cat:10} ${value:7.2f}")
print(f"Total value: ${sum(value_by_category.values()):.2f}")
print("Reorder:", ", ".join(to_reorder))
print("Number of categories:", len(categories))
Output:
Cleaning $ 151.20
Pantry $ 138.70
Dairy $ 86.80
Beverages $ 33.75
Total value: $410.45
Reorder: Peanut butter 16 oz, Cheddar 8 oz
Number of categories: 4
- Cleaning (37%) $151.20Just 18 jugs of detergent: a high unit cost ties up the most cash.
- Pantry (34%) $138.70Rice and peanut butter; peanut butter needs reordering.
- Dairy (21%) $86.80Milk and cheese: fast sellers that expire quickly.
- Beverages (8%) $33.75
d[key] = d.get(key, 0) + value pattern.Notice which structure does each job: the list keeps the products in order; each dictionary names its fields; value_by_category is a dictionary used as an accumulator; .items() returns pairs that are tuples (which is why pair[1] is the value); and the set categories, built with braces in a comprehension, drops duplicates automatically. With 6 products you could do this by hand. With the 2,000 items a real store carries, the code is exactly the same.
4. With prices = [3, 1, 2], what does sorted_prices = prices.sort() followed by print(sorted_prices) display?
.sort() sorts the original list and returns nothing (it returns None). If you want a sorted copy, use sorted_prices = sorted(prices).
Common mistakes with collections
The number one dictionary error is asking for a key that doesn't exist, for example by typing "price" when the key is called "cost":
Traceback (most recent call last):
File "inventory.py", line 2, in <module>
value = item["stock"] * item["price"]
~~~~^^^^^^^^^
KeyError: 'price'
The message only shows the missing key, in quotes. Check how it was spelled when you built the dictionary (capitals included: "Category" and "category" are different keys), or use .get() if the value might be missing.
items = items.sort()
You end up with None. Write just items.sort(), or use sorted(items).
Thinking b = a copies the list.
It's the same list with two names. Copy with a.copy().
Changing a tuple: date[1] = 11.
Tuples are immutable (TypeError: 'tuple' object does not support item assignment). Create a new one or use a list.
items.remove("sugar") without knowing whether it's there.
If it's missing you get ValueError: list.remove(x): x not in list. Check first with if "sugar" in items:.
Searching a whole list to find something by name.
If you look things up by an ID or name, use a dictionary: the lookup is instant.
Practice exercise: a contact book
Write a program with a menu that lets the user:
- Add a contact (name and phone).
- Search for a contact by name.
- List all contacts alphabetically.
- Quit.
See solution
contacts = {}
while True:
option = input("\n1) Add 2) Search 3) List 4) Quit: ")
if option == "1":
name = input("Name: ").strip().title()
phone = input("Phone: ").strip()
contacts[name] = phone
print("Saved")
elif option == "2":
name = input("Who are you looking for? ").strip().title()
print(contacts.get(name, "Not found"))
elif option == "3":
for name in sorted(contacts):
print(f"{name}: {contacts[name]}")
elif option == "4":
break
else:
print("Invalid option")
Because names go through .title(), searching for "ZOE KIM" finds "Zoe Kim." The catch: when you close the program, the contacts disappear. In the next lesson you'll organize this code into functions, and in lesson 8 you'll save it to a file.
Summary
- Lists are ordered and changeable (
append,remove,sort);sorted()returns a copy. - Tuples are immutable, perfect for fixed data and unpacking.
- Dictionaries store key-value pairs; use
.get()for safe access and.items()to loop. - Sets hold unique items and support intersection, union and difference.
- A list of dictionaries represents a table of data, the same shape you'll get from APIs and JSON.
Next lesson: Python Functions: Parameters, return and Modules. You'll package your code into reusable blocks with parameters, default values and return.
Create your account in 30 seconds, mark your lessons and download your certificate at the end.