Unit 12 · lesson

Follow One Object Through the System

Core path: 30 minutes

Object-oriented code gets confusing when students treat the class, the instance, the saved dictionary, and the JSON record as if they are all the same thing.

They are related. They are not identical.

This lesson follows one player all the way through the architecture.

Start with the class

class Player:
    def __init__(self, name, score):
        self.name = name
        self.score = score
        self.rank = self.determine_rank()

The class is the definition of what a Player object should know and what behavior it can provide.

At this point, there is no specific player named Nova yet.

Create an instance

nova = Player("Nova", 850)

Now one instance exists.

Trace the initializer:

name argument = "Nova"
score argument = 850

self.name = "Nova"
self.score = 850

self.determine_rank()

self.rank = "ADVANCED"

The class did not "turn into" Nova. The class was used to create a particular object with its own state.

Prove that two instances are independent

nova = Player("Nova", 850)
maya = Player("Maya", 960)

nova.add_score(100)

After the call:

Nova → score 950
Maya → score 960

self inside nova.add_score(...) refers to Nova's instance.

If Maya changes too, something is wrong with the design or the way shared state was created.

Follow one method call

nova.add_score(100)

The call crosses several steps:

caller selects nova

method receives self = nova

self.score changes

rank is recalculated

control returns to caller

That is a state transition on one object.

Use the debugger and stop inside the method. Inspect self rather than only looking at the final printed score.

Now cross the persistence boundary

Your live object might look conceptually like:

Player instance
name = Nova
score = 950
rank = ELITE
methods available

But JSON needs ordinary data.

So:

nova.to_dict()

produces something like:

{
    "name": "Nova",
    "score": 950,
}

The methods are not saved.

The class definition is not saved into the JSON record.

The file stores enough data to reconstruct the object later.

Stop the process

After saving, terminate the program.

The live nova object disappears with the process.

The JSON remains:

{
  "name": "Nova",
  "score": 950
}

On the next run:

record = {"name": "Nova", "score": 950}
player = Player(record["name"], record["score"])

creates a new Player instance from the persisted data.

It represents the same logical player record, but it is not the same runtime object that existed before shutdown.

That distinction matters.

Derived state can become a trap

Suppose you save:

{
  "name": "Nova",
  "score": 950,
  "rank": "ROOKIE"
}

But your current rank rules say 950 should be ELITE.

Which value should the program trust?

If rank is completely derived from score, storing both values creates a synchronization problem.

A cleaner design may store the authoritative value:

score

and recalculate:

rank

when the object is reconstructed.

That is a source-of-truth decision, not an OOP syntax rule.

Trace your own roster

Pick one real player from Lesson 4 and document:

class definition involved:
constructor arguments:
instance attributes after creation:
method call that changes state:
attributes after method call:
to_dict() result:
JSON representation:
values used during reload:
new instance state after reload:

Then answer:

Which parts belong to the Player model, which belong to storage, and which belong to presentation?

If the answer is "everything belongs in the class because classes are OOP," you have missed the architecture lesson.

The goal is not to turn the whole program into objects.

The goal is to make ownership visible.

Reader workbench

Trace instance state and behavior

This is the Unit's one-file practice surface. Read the code, predict one result, run it, then change a value, input, condition, or boundary and explain why the evidence changed. Multi-file projects, Git, terminals, packages, and live services still belong in the full development workspace.

unit12_practice.py
OutputRun with button or Ctrl/Cmd+Enter
Run the code to see output.
Ready to edit. Press Run when you want evidence.

This runs in an isolated Python worker in your browser. Your edits stay in this browser until you reset them.