Welcome to Module 3, @name! Darwin here with a new programming paradigm.
So far you've learned procedural programming - you wrote functions that process data. Now it's time for Object-Oriented Programming (OOP) - a way of organizing code around objects that combine data and behaviors.
Imagine biological classification. Biologists don't describe every animal from scratch. Instead, they create species with shared characteristics:
In OOP we do the same thing - we create classes as "templates" for objects!
OOP is a programming paradigm based on the concept of objects that contain:
Key OOP concepts:
1# Simple example - biological classification
2
3class Species:
4 """Class representing a species"""
5
6 def __init__(self, name, habitat, diet):
7 """Constructor - initializes the object"""
8 self.name = name
9 self.habitat = habitat
10 self.diet = diet
11
12 def describe(self):
13 """Method - describe the species"""
14 return f"{self.name} lives in {self.habitat} and eats {self.diet}"
15
16# Creating objects (instances of the class)
17lion = Species("Lion", "savanna", "meat")
18python = Species("Python", "jungle", "rodents")
19
20# Using objects
21print(lion.describe()) # "Lion lives in savanna and eats meat"
22print(python.describe()) # "Python lives in jungle and eats rodents"1# Data and functions are separate
2lion_name = "Lion"
3lion_habitat = "savanna"
4lion_diet = "meat"
5
6python_name = "Python"
7python_habitat = "jungle"
8python_diet = "rodents"
9
10def describe_animal(name, habitat, diet):
11 return f"{name} lives in {habitat} and eats {diet}"
12
13print(describe_animal(lion_name, lion_habitat, lion_diet))
14print(describe_animal(python_name, python_habitat, python_diet))
15
16# Problem: Hard to manage many animals!
17# You have to track all variables separately1# Data and functions are together in objects
2class Animal:
3 def __init__(self, name, habitat, diet):
4 self.name = name
5 self.habitat = habitat
6 self.diet = diet
7
8 def describe(self):
9 return f"{self.name} lives in {self.habitat} and eats {self.diet}"
10
11lion = Animal("Lion", "savanna", "meat")
12python = Animal("Python", "jungle", "rodents")
13
14print(lion.describe())
15print(python.describe())
16
17# Advantages:
18# ✅ Data and behaviors are together
19# ✅ Easy to create many objects
20# ✅ Code is more organizedGrouping data and methods in a single object + hiding implementation details.
1class BankAccount:
2 def __init__(self, balance):
3 self.__balance = balance # Private attribute (__)
4
5 def deposit(self, amount):
6 """Public method"""
7 if amount > 0:
8 self.__balance += amount
9
10 def get_balance(self):
11 """Public access to private attribute"""
12 return self.__balance
13
14account = BankAccount(1000)
15account.deposit(500)
16print(account.get_balance()) # 1500
17# print(account.__balance) # Error! Private attributeHiding complexity, showing only the necessary interface.
1class Car:
2 def start_engine(self):
3 """Simple interface"""
4 self.__check_fuel()
5 self.__ignite_spark_plugs()
6 self.__start_motor()
7 print("Engine started!")
8
9 def __check_fuel(self):
10 """Hidden implementation"""
11 pass
12
13 def __ignite_spark_plugs(self):
14 """Hidden implementation"""
15 pass
16
17 def __start_motor(self):
18 """Hidden implementation"""
19 pass
20
21car = Car()
22car.start_engine() # Simple interface - no need to know the details!Creating new classes based on existing ones - a taxonomic hierarchy!
1class Animal:
2 """Base class (parent, superclass)"""
3 def __init__(self, name):
4 self.name = name
5
6 def eat(self):
7 return f"{self.name} eats"
8
9class Mammal(Animal):
10 """Derived class (child, subclass)"""
11 def __init__(self, name, fur_color):
12 super().__init__(name) # Call base class constructor
13 self.fur_color = fur_color
14
15 def nurse_young(self):
16 return f"{self.name} nurses its young with milk"
17
18lion = Mammal("Lion", "golden")
19print(lion.eat()) # Inherited from Animal
20print(lion.nurse_young()) # Own Mammal methodDifferent objects can respond to the same method in different ways.
1class Dog:
2 def speak(self):
3 return "Woof woof!"
4
5class Cat:
6 def speak(self):
7 return "Meow!"
8
9class Cow:
10 def speak(self):
11 return "Moo!"
12
13# Polymorphism - same method, different behaviors
14animals = [Dog(), Cat(), Cow()]
15for animal in animals:
16 print(animal.speak()) # Each one "speaks" differently!1class Species:
2 """
3 Class representing a species in the Safari expedition
4
5 Analogy: A biological species with shared characteristics
6 """
7
8 def __init__(self, scientific_name, common_name, habitat, dangerous=False):
9 """
10 Constructor - initializes a new species
11
12 Args:
13 scientific_name: Scientific name (e.g., "Panthera leo")
14 common_name: Common name (e.g., "Lion")
15 habitat: Natural environment
16 dangerous: Whether dangerous to humans
17 """
18 self.scientific_name = scientific_name
19 self.common_name = common_name
20 self.habitat = habitat
21 self.dangerous = dangerous
22 self.observations = [] # List of observations
23
24 def add_observation(self, location, count, notes=""):
25 """Add a species observation"""
26 observation = {
27 "location": location,
28 "count": count,
29 "notes": notes
30 }
31 self.observations.append(observation)
32 print(f"✓ Added observation: {count}x {self.common_name} in {location}")
33
34 def get_total_observed(self):
35 """Return the total number of observed individuals"""
36 return sum(obs["count"] for obs in self.observations)
37
38 def is_threatened(self):
39 """Check if the species is threatened (fewer than 10 observations)"""
40 return self.get_total_observed() < 10
41
42 def get_status(self):
43 """Return the species status"""
44 total = self.get_total_observed()
45 if total == 0:
46 return "Not observed"
47 elif self.is_threatened():
48 return f"⚠️ Threatened ({total} individuals)"
49 else:
50 return f"✓ Stable ({total} individuals)"
51
52 def describe(self):
53 """Full species description"""
54 danger_status = "⚠️ DANGEROUS" if self.dangerous else "✓ Safe"
55 return f"""
56╔═══════════════════════════════════════════════╗
57 {self.common_name} ({self.scientific_name})
58 Habitat: {self.habitat}
59 Status: {danger_status}
60 Observations: {len(self.observations)}
61 Individuals: {self.get_total_observed()}
62 Condition: {self.get_status()}
63╚═══════════════════════════════════════════════╝
64 """.strip()
65
66# Usage
67lion = Species(
68 scientific_name="Panthera leo",
69 common_name="Lion",
70 habitat="savanna",
71 dangerous=True
72)
73
74# Add observations
75lion.add_observation("Northern Savanna", 5, "Hunting pride")
76lion.add_observation("Rift Valley", 3, "Two adults with cubs")
77lion.add_observation("Serengeti Park", 8)
78
79# Display information
80print(lion.describe())
81print(f"\nTotal observed: {lion.get_total_observed()} lions")
82print(f"Is threatened? {'Yes' if lion.is_threatened() else 'No'}")1def create_species(name, habitat):
2 """Returns a dictionary representing a species"""
3 return {
4 "name": name,
5 "habitat": habitat,
6 "observations": []
7 }
8
9def add_observation(species_dict, location, count):
10 """Modifies the dictionary"""
11 species_dict["observations"].append({"location": location, "count": count})
12
13def get_total(species_dict):
14 """Calculates from the dictionary"""
15 return sum(obs["count"] for obs in species_dict["observations"])
16
17# Usage - functions and data are separate
18lion = create_species("Lion", "savanna")
19add_observation(lion, "North", 5)
20print(get_total(lion))1class Species:
2 def __init__(self, name, habitat):
3 self.name = name
4 self.habitat = habitat
5 self.observations = []
6
7 def add_observation(self, location, count):
8 """Data and logic together!"""
9 self.observations.append({"location": location, "count": count})
10
11 def get_total(self):
12 return sum(obs["count"] for obs in self.observations)
13
14# Usage - data and behaviors together
15lion = Species("Lion", "savanna")
16lion.add_observation("North", 5)
17print(lion.get_total())Advantages of OOP:
Use OOP when:
Use functions/procedures when:
1class Expedition:
2 """
3 Class managing a Safari expedition
4
5 Combines data (location, team, discoveries) and behaviors (adding, reporting)
6 """
7
8 def __init__(self, name, leader, start_date):
9 self.name = name
10 self.leader = leader
11 self.start_date = start_date
12 self.team_members = []
13 self.discovered_species = []
14 self.days_elapsed = 0
15
16 def add_team_member(self, member_name, role):
17 """Add a team member"""
18 member = {"name": member_name, "role": role}
19 self.team_members.append(member)
20 print(f"✓ {member_name} ({role}) joined the expedition")
21
22 def discover_species(self, species_name, location, count=1):
23 """Record a species discovery"""
24 discovery = {
25 "species": species_name,
26 "location": location,
27 "count": count,
28 "day": self.days_elapsed
29 }
30 self.discovered_species.append(discovery)
31 print(f"🔬 Day {self.days_elapsed}: Discovered {count}x {species_name} in {location}")
32
33 def advance_day(self):
34 """Next expedition day"""
35 self.days_elapsed += 1
36 print(f"\n📅 Day {self.days_elapsed} of expedition '{self.name}'")
37
38 def get_statistics(self):
39 """Expedition statistics"""
40 unique_species = len(set(d["species"] for d in self.discovered_species))
41 total_animals = sum(d["count"] for d in self.discovered_species)
42
43 return {
44 "expedition": self.name,
45 "leader": self.leader,
46 "days": self.days_elapsed,
47 "team": len(self.team_members),
48 "unique_species": unique_species,
49 "total_individuals": total_animals
50 }
51
52 def generate_report(self):
53 """Generate expedition report"""
54 stats = self.get_statistics()
55
56 report = f"""
57╔══════════════════════════════════════════════════════════╗
58 EXPEDITION REPORT: {self.name}
59╠══════════════════════════════════════════════════════════╣
60 Leader: {self.leader}
61 Start date: {self.start_date}
62 Days in the field: {stats['days']}
63 Team members: {stats['team']}
64╠══════════════════════════════════════════════════════════╣
65 📊 DISCOVERIES:
66 - Unique species: {stats['unique_species']}
67 - Total individuals: {stats['total_individuals']}
68╠══════════════════════════════════════════════════════════╣
69 👥 TEAM:
70 """
71
72 for member in self.team_members:
73 report += f"\n - {member['name']} ({member['role']})"
74
75 report += "\n╚══════════════════════════════════════════════════════════╝"
76 return report
77
78# Expedition simulation
79expedition = Expedition("Safari 2024", "Dr. Jane Wilson", "2024-06-01")
80
81# Add team
82expedition.add_team_member("Darwin Brown", "Biologist")
83expedition.add_team_member("Alex Chen", "Photographer")
84expedition.add_team_member("Maya Patel", "Guide")
85
86# Expedition days
87expedition.advance_day()
88expedition.discover_species("Panthera leo", "Northern Savanna", 5)
89expedition.discover_species("Loxodonta africana", "Elephant Valley", 12)
90
91expedition.advance_day()
92expedition.discover_species("Python regius", "Jungle", 2)
93expedition.discover_species("Panthera leo", "Southern Savanna", 3)
94
95expedition.advance_day()
96expedition.discover_species("Gorilla gorilla", "Cloud Forest", 8)
97
98# Final report
99print("\n" + expedition.generate_report())In this lesson you learned:
Before moving on:
Safari Analogy: A class is a species (Panthera leo), an object is a specific animal (a specific lion named Simba)!
In the next lesson Darwin will teach you how to create your own classes and objects - you'll build a complete species classification system! 🦁🐍📊