Layer 3 Session 20 State & Interactivity

What Is State in a Program?

Layer 3 begins. Everything so far has been static โ€” built once and read. State is data that legitimately changes while a program runs, and tracking it correctly is a skill of its own.

population 54,000,000 changes over time

Data that is expected to change while the program runs.

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:

  • Define "state" as data that changes over the lifetime of a running program
  • Distinguish construction-time data (Session 15) from data that is expected to change afterward
  • Explain why uncontrolled mutation of shared state causes bugs that are hard to trace
  • Identify which attributes of Country and CountryExplorer are state versus fixed identity
  • Recognise this as a concept-only session, mirroring Session 12's approach

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

Which of these Country attributes is most clearly "state" โ€” data expected to change during the program's life โ€” versus a fixed identifying property?

population is a value we would realistically expect to be updated (Session 14's grow_population) while the program runs โ€” the definition of state. name is closer to a fixed identifying property for the object's lifetime.
Question 2 of 5

A CountryExplorer's .countries list grows as more data loads in. Is that state?

State is not limited to primitive values โ€” any data that legitimately changes while the program runs is state, including collections that grow, shrink, or get reordered.
Question 3 of 5

Two different parts of a program both hold a reference to the same CountryExplorer instance. One part appends a country. What happens from the other part's point of view?

This is Session 05's reference lesson applied to state specifically: if two parts of a program share a reference to the same mutable object, a change made through either one is visible through both โ€” which is powerful, but also the source of many state-related bugs if not managed deliberately.
Question 4 of 5

Why can uncontrolled, scattered mutation of shared state be hard to debug?

If any code, anywhere, can freely mutate shared state, tracing "why is this value wrong" requires checking every possible mutation site instead of one controlled entry point โ€” this is exactly the problem Session 21's controlled updates will address.
Question 5 of 5

Why is this session mostly concept and almost no new syntax?

Just like Session 12 (What Classes Are and Why), this session builds a mental model using tools you already have โ€” attributes and mutation. The next sessions build concrete, controlled patterns for managing it well.

3. The Concept โ€” State

CONSTRUCTIONname, region,population (start)OVER TIMEpopulationkeeps changing

Construction sets the starting values. State is the subset expected to keep changing afterward, through controlled methods.

State is data that changes while the program runs

Every attribute we have written so far has technically been mutable โ€” but not every attribute is meant to change. "State" specifically means data that is expected and designed to change over the lifetime of a running program, in response to something happening.

class Country:
    def __init__(self, name, region, population):
        self.name = name          # fixed identity โ€” not expected to change
        self.region = region      # fixed identity โ€” not expected to change
        self.population = population  # STATE โ€” expected to change over time

Construction-time data vs state

Session 15 established that data arrives explicitly through the constructor. Some of that data stays fixed for the object's lifetime (like name); other data is the object's starting state, expected to evolve afterward (like population, which grow_population already updates).

A collection can be state too

CountryExplorer.countries is state โ€” it grows as data loads, and potentially shrinks or reorders based on user actions later in the project.

class CountryExplorer:
    def __init__(self, countries):
        self.countries = countries  # starts here, but this list is STATE โ€” it changes over time

explorer = CountryExplorer(countries=[])
explorer.countries.append(Country(name="Kenya", region="Africa", population=54000000))
# .countries just changed shape โ€” this is state changing over the program's lifetime

Why uncontrolled mutation is risky

If any part of a large program can reach in and mutate shared state directly, tracing an unexpected value back to its cause becomes very difficult โ€” there is no single place to look. The next several sessions build the discipline of changing state only through deliberate, well-named methods.

# Risky โ€” anyone, anywhere, can silently corrupt state
explorer.countries[0].population = -999999  # no validation, no traceability

# Better (Session 21 formalizes this) โ€” a controlled method with rules
explorer.countries[0].grow_population(1000000)  # validated, named, traceable
Concept-only session: Like Session 12, there is very little new code today. The goal is recognising state as a distinct concept from ordinary attributes before Session 21 gives us controlled patterns for updating it.

4. Lab

Lab objective: Identify and annotate which attributes across the project so far are state versus fixed identity, and observe uncontrolled mutation firsthand.

What you will build

A file called state_concept.py โ€” mostly comments and small demonstrations, not new functionality.

Step-by-step instructions

1

Create the file and re-declare Country and CountryExplorer

# state_concept.py
class Country:
    def __init__(self, name, region, population):
        self.name = name
        self.region = region
        self.population = population

class CountryExplorer:
    def __init__(self, countries):
        self.countries = countries
2

Annotate each attribute with a comment: STATE or FIXED

This is the most important step โ€” write your reasoning, not just a label.

class Country:
    def __init__(self, name, region, population):
        self.name = name              # FIXED โ€” identity, not expected to change
        self.region = region          # FIXED โ€” identity, not expected to change
        self.population = population  # STATE โ€” expected to change over time (Session 14)

class CountryExplorer:
    def __init__(self, countries):
        self.countries = countries    # STATE โ€” grows/shrinks as data loads (Session 16)
3

Demonstrate uncontrolled mutation directly and observe it works with no guardrails

k = Country(name="Kenya", region="Africa", population=54000000)
k.population = -999999   # directly assigned, bypassing any validation
print(k.population)      # -999999 โ€” nothing stopped this
4

Demonstrate two references sharing the same mutable state

Recall Session 05 โ€” prove it applies to real objects too, not just dicts.

explorer = CountryExplorer(countries=[k])
same_explorer = explorer  # NOT a copy โ€” same reference

same_explorer.countries.append(Country(name="Ghana", region="Africa", population=31000000))
print(len(explorer.countries))       # 2 โ€” the change is visible through BOTH names
print(len(same_explorer.countries))  # 2
5

Write a short comment describing the risk you just observed

No new code required โ€” summarize, in your own words, why direct attribute assignment (step 3) is risky compared to a controlled method.


5. Expected Files Changed

FileActionWhy
state_concept.py Created Identifies state vs fixed attributes and demonstrates uncontrolled mutation risk.
docs/sessions/session-20/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 state_concept.py docs/sessions/session-20/index.html
git commit -m "session-20: identify state vs fixed attributes and observe uncontrolled mutation risk"
Do not commit until you can answer out loud: "In my own words, what makes population "state" while name is not?"

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

Which of these Country attributes is most clearly "state" โ€” data expected to change during the program's life โ€” versus a fixed identifying property?

population is a value we would realistically expect to be updated (Session 14's grow_population) while the program runs โ€” the definition of state. name is closer to a fixed identifying property for the object's lifetime.
Question 2 of 5

A CountryExplorer's .countries list grows as more data loads in. Is that state?

State is not limited to primitive values โ€” any data that legitimately changes while the program runs is state, including collections that grow, shrink, or get reordered.
Question 3 of 5

Two different parts of a program both hold a reference to the same CountryExplorer instance. One part appends a country. What happens from the other part's point of view?

This is Session 05's reference lesson applied to state specifically: if two parts of a program share a reference to the same mutable object, a change made through either one is visible through both โ€” which is powerful, but also the source of many state-related bugs if not managed deliberately.
Question 4 of 5

Why can uncontrolled, scattered mutation of shared state be hard to debug?

If any code, anywhere, can freely mutate shared state, tracing "why is this value wrong" requires checking every possible mutation site instead of one controlled entry point โ€” this is exactly the problem Session 21's controlled updates will address.
Question 5 of 5

Why is this session mostly concept and almost no new syntax?

Just like Session 12 (What Classes Are and Why), this session builds a mental model using tools you already have โ€” attributes and mutation. The next sessions build concrete, controlled patterns for managing it well.

9. Reflection Questions

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

  1. Is region truly always fixed? Can you think of a real-world scenario (e.g. historical border changes) where it might legitimately need to be state instead?
  2. Why do you think this session deliberately shows you the RISK of uncontrolled mutation before Session 21 shows you the SOLUTION?
  3. How does "two references sharing mutable state" in this session's lab connect back to Session 05's object mutation, Session 13's independent instances, and Session 16's composition?
  4. Where in a large real application would uncontrolled state mutation be catastrophic versus merely annoying?

10. What Breaks If This Knowledge Is Missing?

  • Untraceable bugs: A program where any code anywhere can mutate any state directly makes "why is this value wrong" a search through the entire codebase instead of a single, well-known method โ€” this is the single most common source of hard-to-debug real-world software issues.
  • Controlled updates (Session 21): The next session channels all state changes through named, validating methods. Without today's clear sense of what counts as state, that discipline will feel like unnecessary ceremony instead of a direct fix for a problem you just observed yourself.
  • Re-render logic (parallel to the original course's Session 23): This mirrors exactly why the source React course treats state as sacred โ€” uncontrolled mutation there breaks UI updates. Here, it breaks traceability. The underlying discipline is the same.

11. What We Learned

Python concept mastered: State โ€” data expected to change during a program's run, distinct from fixed identity data, and the risk of mutating it without a controlled entry point.

Unlocks: You can now identify state in any class you design, and you have directly observed why uncontrolled mutation is a real problem, not a theoretical one.

Next session: Session 21 โ€” Updating State via Methods. We formalize controlled state updates through named, validating methods โ€” turning the risk from this session into a solved problem.