Layer 2 Session 12 Object-Oriented Basics

What Classes Are and Why

Layer 2 begins. A dictionary describes data. A class describes a kind of thing โ€” data plus the behavior that belongs with it. This is why we are switching.

class Country Kenya Peru Ghana

A blueprint for a kind of thing, and the things built from it.

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:

  • Explain the difference between a dictionary and a class conceptually
  • Define an empty class and create an instance of it
  • Explain what an instance is, versus the class itself
  • Explain why grouping data with the behavior that operates on it reduces bugs
  • Recognise that this session is concept-only โ€” no meaningful code is written yet

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

Given country = {"name": "Kenya"} and class Country: pass then c = Country(), what is the core difference between country and c?

A dictionary only ever holds data. A class defines both the shape of its data (via attributes) and the operations that belong with it (via methods) โ€” a coherent bundle rather than a bag of values.
Question 2 of 5

What does class Country: pass define?

pass is a no-op placeholder statement, used here because a class body cannot be syntactically empty. This defines a minimal, valid class with nothing in it yet.
Question 3 of 5

What is c in c = Country()?

Calling a class with () constructs a new instance โ€” a specific, individual object that belongs to that class. Country is the blueprint; c is one thing built from it.
Question 4 of 5

If you defined a second instance c2 = Country(), is c the same object as c2?

Just like calling a function twice runs it twice, calling a class twice constructs two separate, independent instances โ€” even though they came from the same blueprint.
Question 5 of 5

Why is bundling data and the functions that operate on it (inside a class) considered better than passing loose dictionaries to loose functions everywhere?

When behavior lives on the class itself, anyone reading the code can find "everything a Country can do" in one place, and the class can enforce that its own data stays valid โ€” something a loose dictionary and scattered functions cannot guarantee.

3. The Concept โ€” Why Classes Exist

CLASSCountry(the blueprint)INSTANCEc = Country()

Country is the blueprint. c is one specific instance built from that blueprint โ€” a second call would build a separate one.

What we have been doing so far

For seven sessions, a country has been a dictionary, and every operation on it โ€” formatting, filtering, validating โ€” has been a separate, standalone function that takes the dictionary as an argument. This works, but nothing stops any function anywhere from reading or writing the wrong key, or writing an invalid value.

country = {"name": "Kenya", "population": 54000000}

def set_population(country, value):
    if value < 0:
        raise ValueError("population must be positive")
    country["population"] = value

# Nothing stops this โ€” the dict has no memory of the rule above
country["population"] = -100

A class bundles data and behavior together

A class is a blueprint for a kind of thing. It groups the data that thing needs (its attributes) with the operations that belong to it (its methods) into a single definition. We will build this up piece by piece over the next several sessions โ€” today, just the shell.

class Country:
    pass  # placeholder โ€” a class body cannot be empty

c = Country()
print(type(c))     # <class '__main__.Country'>
print(isinstance(c, Country))  # True

Class vs instance โ€” a critical distinction

The class is the definition, written once. An instance is a specific object built from that definition โ€” you can build as many as you need, and each one is independent, just like each call to a function produces an independent result.

c1 = Country()
c2 = Country()
print(c1 is c2)  # False โ€” two separate instances, even though both are Country

What this unlocks

Right now Country is an empty shell โ€” it does nothing a dictionary couldn't already do. Over the next several sessions we will give it attributes (Session 13), methods (Session 14), a proper constructor (Session 15), and eventually a whole tree of related classes (Session 16) โ€” building toward a real Country Explorer application.

Concept-only session: There is intentionally very little code today. The goal is to genuinely understand WHY we are switching from dictionaries to classes before writing the class itself in the next session.

4. Lab

Lab objective: Define an empty Country class, create two separate instances, and prove they are independent objects โ€” no meaningful behavior yet.

What you will build

A file called country_class.py.

Step-by-step instructions

1

Create the file and define an empty class

# country_class.py
class Country:
    pass
2

Create two separate instances

c1 = Country()
c2 = Country()

print(c1)
print(c2)
3

Confirm both are instances of Country

print(isinstance(c1, Country))  # True
print(isinstance(c2, Country))  # True
4

Prove they are two distinct objects, not the same one

Before running: predict what c1 is c2 will print, and why.

print(c1 is c2)  # False โ€” separate objects in memory
5

Write a short comment explaining what problem this will eventually solve

No code required here โ€” write a plain-English comment in the file summarising, in your own words, why a class beats a loose dict + loose functions. This is the most important step in the lab.

# TODO: In your own words โ€” why will bundling country data and
# country behavior into one class reduce bugs compared to
# passing a dict to a bunch of separate functions?

5. Expected Files Changed

FileActionWhy
country_class.py Created An empty Country class and proof that instances are independent.
docs/sessions/session-12/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 country_class.py docs/sessions/session-12/index.html
git commit -m "session-12: define an empty Country class and confirm instances are independent"
Do not commit until you can answer out loud: "In my own words, what is the difference between the Country class and a Country instance?"

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

Given country = {"name": "Kenya"} and class Country: pass then c = Country(), what is the core difference between country and c?

A dictionary only ever holds data. A class defines both the shape of its data (via attributes) and the operations that belong with it (via methods) โ€” a coherent bundle rather than a bag of values.
Question 2 of 5

What does class Country: pass define?

pass is a no-op placeholder statement, used here because a class body cannot be syntactically empty. This defines a minimal, valid class with nothing in it yet.
Question 3 of 5

What is c in c = Country()?

Calling a class with () constructs a new instance โ€” a specific, individual object that belongs to that class. Country is the blueprint; c is one thing built from it.
Question 4 of 5

If you defined a second instance c2 = Country(), is c the same object as c2?

Just like calling a function twice runs it twice, calling a class twice constructs two separate, independent instances โ€” even though they came from the same blueprint.
Question 5 of 5

Why is bundling data and the functions that operate on it (inside a class) considered better than passing loose dictionaries to loose functions everywhere?

When behavior lives on the class itself, anyone reading the code can find "everything a Country can do" in one place, and the class can enforce that its own data stays valid โ€” something a loose dictionary and scattered functions cannot guarantee.

9. Reflection Questions

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

  1. Before this session, every "operation" on a country was a standalone function taking a dict. Can you think of a bug you might have written in the labs so far that a class could have prevented?
  2. Why do you think Python requires pass for an empty class body instead of allowing nothing at all?
  3. What is the relationship between a class and the type() of an instance built from it?
  4. If two instances of the same class can hold completely different data, what does that tell you about what a class actually "is" versus what an instance "is"?

10. What Breaks If This Knowledge Is Missing?

  • Confusing the class with an instance: If you don't internalize the class/instance distinction now, later sessions (attributes, methods, inheritance) will feel like memorized syntax instead of a coherent mental model โ€” and debugging "why does every instance share this value" bugs becomes very hard.
  • Attribute sessions ahead: Session 13 immediately builds on this by giving Country actual data via __init__. Without today's "class = blueprint, instance = built thing" model, __init__ will look like arbitrary magic syntax instead of a logical next step.

11. What We Learned

Python concept mastered: The class vs instance distinction, and the motivation for bundling data with behavior instead of using loose dicts and functions.

Unlocks: You have a mental model for what a class is FOR. Every remaining Layer 2 session builds directly on top of this.

Next session: Session 13 โ€” Class Anatomy โ€” __init__ and Attributes. We give Country real data โ€” an __init__ method and instance attributes, so every instance can hold its own name, region, and population.