Chapter 9: Bundling State & Behavior (OOP)
Learning Objectives
- Understand the chaos of disconnected variables and functions.
- Master the concepts of Classes (blueprints) and Objects (instances).
- Learn how
thisorselfconnects behavior to specific memory boxes. - Write your first Object-Oriented program.
Prerequisites
Chapter 5: Functions & Scope. Chapter 7: Hash Maps.
Why Does This Exist?
Imagine building a game with 100 enemies.
Without OOP, you need arrays for everything: enemy_health = [100, 50, ...], enemy_x = [10, 20, ...]. If you want Enemy 5 to take damage, you must pass index 5 into a global take_damage(index, amount, health_array) function.
This is brittle. If the arrays get out of sync, Enemy 5 takes damage but Enemy 6 dies.
We needed a way to glue State (Variables: health, position) and Behavior (Functions: take_damage, move) together into a single, cohesive package.
History
Early languages like C had "Structs" which could group variables together, but functions were still separate.
In the 1970s, languages like Smalltalk pioneered Object-Oriented Programming (OOP). The radical idea was that code shouldn't be a list of top-down instructions. It should be a collection of independent "Objects" sending messages to each other, much like biological cells in a body.
Mental Model
A Class is an architectural blueprint. It defines what a House should have (3 bedrooms, 1 door) and what it can do (open door).
An Object (or Instance) is the actual, physical house built from that blueprint.
You can use one blueprint to build 10,000 houses. They all share the same layout (behavior), but they have different families living inside them (state).
Internal Working
How does a generic class function know which specific object's health to modify?
Under the hood, every time you call an object's method like enemy5.take_damage(10), the compiler secretly rewrites it to take_damage(enemy5, 10).
It passes a hidden pointer (usually called self or this) representing the specific memory address of enemy5 into the function. The CPU uses this pointer to find the exact chunk of RAM holding Enemy 5's health, ignoring the other 99 enemies.
Syntax
Here is how we define a blueprint in Python:
1class Player:
2 def __init__(self, name):
3 self.name = name
4 self.health = 100
5
6 def take_damage(self, amount):
7 self.health = self.health - amount
Token breakdown:
class: The keyword to define a blueprint.__init__: The "Constructor". This function runs automatically the exact moment you build a new physical house. It sets up the initial state.self: The magical hidden pointer. It means "MY specific memory address".self.health: This creates a variable that lives inside the object, not locally in the function.
Visual Explanation
Tiny Example
1p1 = Player("Hero")
2p1.take_damage(20)
3print(p1.health) # Output: 80
Walkthrough
- Line 1: The CPU allocates a block of memory for a new Object. It calls the
__init__function, secretly passing the new memory address asself, and "Hero" as the name. - Line 2: We call a behavior on the object using the dot
.operator. The CPU jumps to the class code, passingp1asself, and 20 as the amount. - Line 3: We access the state (property) directly and print it.
Common Mistakes
Forgetting Self
1class Dog:
2 def bark(): # BAD: Missing self
3 print("Woof")
4
5d = Dog()
6d.bark()
Why it fails: The computer automatically tries to pass the object's memory address into the function. But the function isn't expecting any arguments! It throws a TypeError: bark() takes 0 arguments but 1 was given.
The Fix: Always include self as the first parameter in class methods.
Debugging
When an object isn't behaving properly, you need to see its internal state.
Professionals don't guess. In Python, you can use the built-in __dict__ property to view all internal state of an object instantly as a dictionary.
print(p1.__dict__)
Outputs: {'name': 'Hero', 'health': 80}
Mini Project
Time: 20 minutes.
Goal: The Bank Account.
Create a BankAccount class. The __init__ should set an owner name and a balance of 0. Create two methods: deposit(amount) and withdraw(amount). Create an instance, deposit 100, withdraw 50, and print the balance.
Bigger Project
Time: 1.5 hours.
Goal: Tamagotchi Pet.
Create a Pet class. It has hunger, energy, and happiness. Create methods to feed(), sleep(), and play(). Each action should affect multiple stats (e.g., playing increases happiness but decreases energy and increases hunger). Write a while True loop allowing the user to type actions in the console to keep the pet alive.
Production Usage
Virtually all major enterprise software is Object-Oriented.
In an e-commerce backend, a ShoppingCart is a class. When you click "Add to Cart", a controller calls cart.add_item(product). The cart calculates its own total, manages its own taxes, and eventually calls cart.checkout().
Best Practices
- Encapsulation: Objects should manage their own state. You shouldn't manually do
player.health = 0from outside the class. You should callplayer.take_damage(999)so the class can run its own death animations or logic. - Don't Force It: Not everything needs to be a class. If you have a simple math formula, a standalone Function is fine. Use classes when State and Behavior naturally belong together.
Interview Questions
Easy: What is a Constructor?
Answer: A special method that automatically runs when an object is instantiated, used to initialize the object's default state.
Medium: Explain the difference between a Class and an Object.
Answer: A class is the definition/blueprint (code). An object is an instance of that class living in memory (data).
Hard: What is Polymorphism?
Answer: The ability for different classes to share the same method name, but implement it differently. If Dog and Cat both have a speak() method, you can loop through an array of mixed animals and call animal.speak(), and the CPU dynamically figures out which specific method to run.
Revision Sheet
- Class: The blueprint defining state and behavior.
- Object/Instance: The physical memory block created from the blueprint.
- State: Variables tied to the object (Attributes/Properties).
- Behavior: Functions tied to the object (Methods).
- self/this: The pointer connecting the generic code to the specific memory instance.
Connections
- Previous Chapter: Under the hood, an Object's state is often just stored in a hidden Dictionary/Hash Map inside the CPU.
- Future Chapters: We will learn how to save the state of these Objects permanently to a hard drive using File I/O (Chapter 11).