Layer 1 Session 06 Python Foundations

Lists and Iteration

A single country dictionary is not a country explorer. We need to hold many of them โ€” that means lists, indexing, and loops.

"Kenya"0"Ghana"1"Peru"2"Japan"3index โ†’

An ordered, indexed sequence of values.

Estimated time: 35โ€“40 minutes  ยท  Pre-quiz โ†’ Concept โ†’ Lab โ†’ Commit โ†’ Post-quiz

1. Learning Objective

By the end of this session you will be able to:

  • Create a list using literal syntax and understand that it is ordered and mutable
  • Access items by index, including negative indexing
  • Use len() and iterate with a for loop
  • Explain the difference between mutating methods (.append, .sort) and non-mutating operations
  • Store a list of dictionaries โ€” the shape our whole project will use

2. Pre-Coding Quiz

Answer these before reading the concept explanation or writing any code. It is fine to get these wrong โ€” that is the point. You need 4/5 to proceed to the lab.

Question 1 of 5

You have countries = ["Kenya", "Ghana", "Peru"]. What does countries[1] return?

Python lists are zero-indexed. Index 0 is "Kenya", index 1 is "Ghana", index 2 is "Peru".
Question 2 of 5

What does countries[-1] return for the same list?

Negative indices count from the end. -1 is always the last item, -2 the second-to-last, and so on. This avoids writing countries[len(countries) - 1].
Question 3 of 5

What is printed by:
nums = [3, 1, 2]
nums.append(9)
print(nums)

.append() is a mutating method โ€” it adds to the existing list object and returns None. It does not create a new list.
Question 4 of 5

You loop with for country in countries:. On each iteration, what does country refer to?

A for ... in loop over a list binds the loop variable to each element's value in turn โ€” not the index. Use enumerate() when you need both the index and the value.
Question 5 of 5

You want each item in the loop to be a dictionary you can read fields from, e.g. country["name"]. What must countries be?

For country["name"] to work inside the loop, each element yielded by the loop must itself be a dict. That means countries is a list whose elements are dicts โ€” exactly the shape we build in this session's lab.

3. The Concept โ€” Python Lists and Iteration

INDEX 0"Kenya"INDEX 1"Ghana"INDEX 2 / -1"Peru"

Index counts up from 0 on the left, and down from -1 on the right โ€” both point into the same list.

What is a list?

A list is an ordered, mutable sequence of values. Unlike a dictionary, items are accessed by position (index), not by name.

countries = ["Kenya", "Ghana", "Peru"]

print(countries[0])   # "Kenya"  โ€” first item, index 0
print(countries[1])   # "Ghana"
print(countries[-1])  # "Peru"   โ€” last item, negative index
print(len(countries)) # 3

Iterating with a for loop

The most common way to process every item in a list is a for ... in loop. No manual index counting required.

countries = ["Kenya", "Ghana", "Peru"]

for country in countries:
    print(country)
# Kenya
# Ghana
# Peru

# When you need the index too, use enumerate()
for i, country in enumerate(countries):
    print(i, country)
# 0 Kenya
# 1 Ghana
# 2 Peru

Mutating vs non-mutating operations

Some list methods change the list in place and return None. Others return a new value and leave the original untouched. Confusing the two is a very common bug.

nums = [3, 1, 2]

nums.append(9)     # mutates in place -> [3, 1, 2, 9]
nums.sort()         # mutates in place -> [1, 2, 3, 9]

# sorted() is non-mutating โ€” it returns a NEW list
original = [3, 1, 2]
result = sorted(original)
print(original)  # [3, 1, 2] โ€” unchanged
print(result)    # [1, 2, 3] โ€” new list
.SORT()nums โ†’ [1, 2, 3, 9](same object)SORTED()original unchangedresult = new list

.sort() mutates the original object; sorted() leaves it alone and hands back a new list.

A list of dictionaries โ€” our project's core data shape

Combining what we learned in Session 05 with lists gives us exactly what a real application needs: a collection of structured records.

countries = [
    {"name": "Kenya", "region": "Africa", "population": 54000000},
    {"name": "Ghana", "region": "Africa", "population": 31000000},
    {"name": "Peru",  "region": "Americas", "population": 33000000},
]

for country in countries:
    print(country["name"], "-", country["region"])
# Kenya - Africa
# Ghana - Africa
# Peru - Americas
Why this matters for the project: Every screen of our Country Explorer app โ€” search, filtering, display โ€” starts from exactly this shape: a list of dictionaries. Everything from here forward operates on this structure.

4. Lab

Lab objective: Store three countries as a list of dictionaries, iterate over it, and prove the mutating vs non-mutating distinction.

What you will build

A file called countries.py that builds on Session 05's single dictionary.

Step-by-step instructions

1

Create the file

# countries.py
2

Build a list of at least 3 country dictionaries

Reuse the shape from Session 05 โ€” each item needs at least name, region, and population.

countries = [
    {"name": "Kenya", "region": "Africa", "population": 54000000},
    {"name": "Ghana", "region": "Africa", "population": 31000000},
    {"name": "Peru",  "region": "Americas", "population": 33000000},
]
3

Iterate and print each country's name

Use a plain for loop, no enumerate yet.

for country in countries:
    print(country["name"])
4

Iterate with enumerate() to also print position

for i, country in enumerate(countries):
    print(f"{i}: {country['name']}")
5

Add a country with .append()

Print the list before and after to confirm it mutated in place.

print("Before:", len(countries))
countries.append({"name": "Japan", "region": "Asia", "population": 125000000})
print("After:", len(countries))
6

Prove sorted() does not mutate

Sort the country names alphabetically without touching the original list.

names = [c["name"] for c in countries] if False else None  # ignore, next session
name_list = ["Peru", "Ghana", "Kenya", "Japan"]
sorted_names = sorted(name_list)
print("Original order:", name_list)
print("Sorted copy:", sorted_names)
7

Access the last item with negative indexing

print("Last country added:", countries[-1]["name"])

5. Expected Files Changed

FileActionWhy
countries.py Created Builds a list of dictionaries and demonstrates iteration.
docs/sessions/session-06/index.html Created This session document.
If you find yourself editing any other file, stop. This session touches exactly 2 files.

6. Commit Checkpoint

Once the lab is complete and you can explain every line, make this exact commit:

git add countries.py docs/sessions/session-06/index.html
git commit -m "session-06: store countries in a list, iterate, and separate mutating from non-mutating ops"
Do not commit until you can answer out loud: "What is the difference between .sort() and sorted(), and why does it matter?"

7. Code Review Checklist

Go through your code line by line and check each item:


8. Post-Coding Quiz

Same 5 questions. Take it again now that you have written and run the code. You need 4/5 to mark this session complete.

Question 1 of 5

You have countries = ["Kenya", "Ghana", "Peru"]. What does countries[1] return?

Python lists are zero-indexed. Index 0 is "Kenya", index 1 is "Ghana", index 2 is "Peru".
Question 2 of 5

What does countries[-1] return for the same list?

Negative indices count from the end. -1 is always the last item, -2 the second-to-last, and so on. This avoids writing countries[len(countries) - 1].
Question 3 of 5

What is printed by:
nums = [3, 1, 2]
nums.append(9)
print(nums)

.append() is a mutating method โ€” it adds to the existing list object and returns None. It does not create a new list.
Question 4 of 5

You loop with for country in countries:. On each iteration, what does country refer to?

A for ... in loop over a list binds the loop variable to each element's value in turn โ€” not the index. Use enumerate() when you need both the index and the value.
Question 5 of 5

You want each item in the loop to be a dictionary you can read fields from, e.g. country["name"]. What must countries be?

For country["name"] to work inside the loop, each element yielded by the loop must itself be a dict. That means countries is a list whose elements are dicts โ€” exactly the shape we build in this session's lab.

9. Reflection Questions

Think through these after the post-quiz. No right answer โ€” they are for discussion.

  1. Why do you think Python chose zero-based indexing instead of starting at 1?
  2. If .append() mutates in place and returns None, what would countries = countries.append(x) incorrectly leave countries as? Try it.
  3. When would negative indexing actually save you from an error-prone calculation?
  4. Why is "a list of dictionaries" a more useful shape than three separate parallel lists (names, regions, populations)?

10. What Breaks If This Knowledge Is Missing?

  • The append-return bug: A very common beginner mistake is writing x = some_list.append(item), expecting x to be the updated list. It is actually None, because mutating methods return nothing. This trips people up for years if never explained explicitly.
  • List comprehensions (Session 07): The next session builds directly on for-loop iteration. If you cannot trace what a for loop does step by step, list comprehensions will look like meaningless syntax instead of a shorthand for something you already understand.
  • Testing (Layer 5): Later, you will write tests that assert on list contents and order. Without understanding indexing and iteration, you cannot reason about what a test assertion is actually checking.

11. What We Learned

Python concept mastered: Lists โ€” indexing (including negative), len(), for-loop iteration, enumerate(), mutating vs non-mutating operations.

Unlocks: You can now hold and process a real collection of records โ€” the shape our whole Country Explorer project uses.

Next session: Session 07 โ€” List Comprehensions. We will learn to transform and filter this list without a manual for-loop, using list comprehensions.