Classes and Objects Basics
In Lesson 1, you discovered WHY OOP exists. Now you'll learn the syntax for HOW to create classes and objects through hands-on experimentation with real-world domain examples, starting with Task management that you'll build throughout Part 5.
Part 1: Experience Classes by Experimentation
Your Role: Code explorer discovering how Python implements objects
Before reading syntax explanations, you'll experiment with creating classes to develop intuition.
Discovery Exercise: Build Classes Step by Step
What is a class? A class is a blueprint (template) for creating objects. Think of it like a task template: the class defines what properties a task can have, and objects are the individual tasks you create from it. The class keyword in Python defines this blueprint.
Stage 1: The Simplest Possible Class
Let's create the simplest possible class - a blueprint with no details yet.
Create a file called task_experiments.py and run this code:
Loading Python environment...
Your task 1: Run this and document:
- What does
type(my_task)tell you? - What does
print(my_task)show you? (Pay attention to the memory address) - What's in
dir(my_task)? What default methods does Python give every object?
Output:
<class 'task_experiments.Task'>
<task_experiments.Task object at 0x7f8b8c0d5f90>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subattr__', '__subclasshook__', '__weakref__', '__dict__']
💬 AI CoLearning Prompt
"I created an empty class with just
pass. When I inspectdir(my_task), I see lots of methods like__init__,__str__,__dict__. Where do these come from? What's the relationship between a class and an object? Explain using a cookie-cutter analogy, then connect it to how a Task template and individual tasks work together."
Expected Understanding: AI will explain that classes are blueprints/templates (cookie cutter or task template), objects are instances created from them (cookies or individual tasks). Python gives every object default methods automatically. You'll understand the class-object relationship before coding more.

Stage 2: Add Data to Task Objects
Pedagogical Note: In this stage, we'll show you a way to add data to objects that WORKS but isn't the professional pattern. We're doing this deliberately so you understand WHY the proper pattern (constructors with __init__) exists. Discovery through contrast is powerful.
Now modify the code to represent real tasks:
Loading Python environment...
Your task 2: Run this and answer:
- How do you add data to an object in Python?
- Are the objects independent? Prove it.
- What happens if you inspect
my_task.__dict__? (This shows all attributes)
Output:
Task: Review pull request
Done: False
Priority: 2
Task: Deploy to production
Priority: 1
After changing my_task priority to 5:
my_task priority: 5
important_task priority: 1
💬 AI CoLearning Prompt
"I'm adding attributes to Task objects using
my_task.title = 'Review PR'. This works, but I have to repeat this for EVERY task I create. For 100 tasks, that's 300+ lines of attribute assignment! How do professional developers avoid this repetition? What Python feature lets me initialize task attributes automatically when creating a Task object? Give me a preview of the solution before I learn the syntax."
Expected Understanding: AI will preview the __init__ method (constructor) that automatically runs when you create an object. You'll see WHY constructors exist before learning HOW they work. This motivates the learning in Part 2.
Stage 3: Notice the Problem with Manual Attributes
You've seen that adding attributes manually works. Now let's see why it's problematic at scale.
Loading Python environment...
Your task 3: Before reading further, predict:
- What would solve the repetition problem?
- How could you ensure every Task object MUST have title: str, done: bool, priority: int?
- What language feature would enforce this at object creation time?
Answer Preview: The solution is the constructor (__init__ method) with type hints. You'll learn this in the next section. This discovery exercise showed you the PAIN that constructors solve.
Your Discovery Summary
Instead of manual documentation, use AI to synthesize what you learned:
💬 AI CoLearning Prompt
"Based on my experiments with creating Task classes and adding attributes manually, summarize these key insights:
- What's the relationship between classes and objects? (blueprint vs instance)
- How are Task objects independent? (each has its own memory)
- What's the pain point with manual attribute assignment? (repetition, no enforcement)
- What's the solution I'm about to learn? (constructors with init)
Give me 3 concise bullet points I can reference in Part 2."
Deliverable: Save AI's synthesis in your notes. You've discovered the problem—now you're ready to learn the solution (__init__ method) in Part 2.
Part 2: Learn Class Syntax and Constructors with Task Methods
Your Role: Student receiving instruction from AI Teacher
Now that you've experienced the limitations of manual attribute setting, it's time to learn the solution using real Task management patterns.

AI Teaching Prompt
Ask your AI companion:
"I've been creating Task objects and manually adding title, done, priority attributes to each one. This is repetitive:
Loading Python environment...
How can I force every Task to automatically initialize with title, done, priority when created? Show me the syntax and explain:
- What is the
__init__method?- What is
self?- Why does Python require explicit
selfparameter?- Show me the same task-creating code but using init"
What You'll Learn from AI
Expected AI Response (summary):
__init__method: A special constructor that Python automatically calls when you create an objectself: Represents "the object being created." It's always the first parameterself.title = title: Creates an attribute on THIS object- Why explicit self?: Python wants you to be clear: you're setting attributes on a specific object
AI will show you:
Loading Python environment...
Output:
Review pull request
Deploy to production
2
1
Convergence Activity
After AI explains, test your understanding:
Ask AI: "Walk me through what happens in memory when I call Task('Review PR', priority=2). Step by step: Python creates the object, then calls __init__ with what self value? Show me how Python internally handles the 'self' parameter."
Deliverable: Write a summary explaining __init__, self, and why this solves the repetition problem compared to manual attribute setting.
Part 3: Design Task Methods for State Changes
Your Role: Student designing behavior through instance methods
Now that you understand how to initialize Task objects, let's add methods that represent real task operations.
Working with Task Methods
Real tasks need to DO things. Let's design methods that represent task operations:
Loading Python environment...
Output:
Review pull request [○ Pending] - Priority: 2
Priority updated to 1
Review pull request [✓ Complete] - Priority: 1
Task 'Review pull request' marked as complete
💬 AI CoLearning Prompt
"I've defined Task methods like
mark_complete()andupdate_priority(). When I calltask1.mark_complete(), how does Python know to modify task1's attributes, not task2's? Walk me through the method call: Python seestask1.mark_complete(), internally it must do something likeTask.mark_complete(task1). Explain how the self parameter makes this work automatically without me typing the object name."
Challenge: Object Independence with Methods
Your prompt to AI:
"I create two Task objects and modify one:
Loading Python environment...
After this, what are:
task1.done?task1.priority?task2.done?task2.priority?Why didn't task2 change when I modified task1? Explain what's happening in memory that makes them separate."
Expected learning: AI will explain that each object has its own memory space for attributes. This is the fundamental power of objects. Methods operate on specific instances.
Output:
task1.done = True
task1.priority = 5
task2.done = False
task2.priority = 1
# task2 is independent!
Part 4: Pattern Transfer Across Domains
Your Role: Knowledge synthesizer discovering pattern universality
You've learned classes using Task. Now you'll see that these SAME PATTERNS apply to completely different domains.
Domain Transfer: Legal, Finance, Healthcare
The Task class pattern appears everywhere. Here's how it transfers:
Domain 1: Legal Case Management
Loading Python environment...
Output:
Case: Smith v. Jones - Status: open
Case 2025-CV-1234 closed
Domain 2: Finance Invoice Management
Loading Python environment...
Output:
Invoice INV-2025-001: $5000.0
Discount applied: $500.00
After discount: $4500.0
Domain 3: Healthcare Appointment Scheduling
Loading Python environment...
Output:
Appointment with Dr. Smith
Appointment APT-2025-0001 confirmed
Rescheduled with Dr. Johnson
Pattern Comparison Table
| Pattern | Task | Case | Invoice | Appointment |
|---|---|---|---|---|
| Attributes | title, done, priority | case_number, status, client | invoice_id, amount, is_paid | appointment_id, is_confirmed |
| Constructor | __init__(title, priority) | __init__(case_number, title) | __init__(invoice_id, amount) | __init__(appointment_id, patient) |
| Key method | mark_complete() | close_case() | mark_paid() | confirm() |
| Status change | done → True | status → "closed" | is_paid → True | is_confirmed → True |
Key insight: The PATTERN is identical across all domains. Only the data and method names change. You're not learning Task-specific syntax—you're learning a universal Python pattern.
💬 AI CoLearning Prompt
"I've now seen Task, Case, Invoice, and Appointment classes. They all follow the same pattern:
- Constructor initializes attributes
- Methods modify that state
- Each object maintains independent state
What's the universal pattern here? If I encounter a completely new domain (e.g., Product inventory, Restaurant reservation, Library book), how would I design a class using what I've learned?"
Deliverable: Write a summary showing how the Task pattern applies universally.
Part 5: Build Your Class Design Patterns Reference
Your Role: Knowledge synthesizer creating design templates
Now integrate everything into reusable patterns for designing classes in any domain.
Your Class Design Template
Create a markdown file called class_design_patterns.md with this structure:
# Class Design Patterns
## Pattern 1: Simple Data Container with State Methods
**When to use**: Class representing a real-world entity with state and operations
**Template**:
```python
class Entity:
def __init__(self, required_attr: str, optional_attr: str = "default"):
self.required_attr = required_attr
self.optional_attr = optional_attr
self.status = "initial_state"
def perform_action(self) -> None:
"""Describe what this method does."""
self.status = "new_state"
Key points:
- Constructor parameters match required attributes
- Type hints on parameters
- Status attributes track entity state
- Methods change state through self.attribute assignments
Pattern 2: Methods with Parameters
When to use: Methods that modify state based on input
Template:
Loading Python environment...
Key points:
- Parameters enable method flexibility
- Validation happens in methods
- Methods can raise exceptions for invalid input
- Always use type hints
Pattern 3: Methods with Return Values
When to use: Methods that compute or retrieve data
Template:
Loading Python environment...
Key points:
- Use return type hints (-> type)
- Methods should return data, not just print
- Callers can use returned values
Pattern 4: Object Independence Verification
How to verify objects are truly independent:
Loading Python environment...
Why this matters: Confirms that each object has its own memory space.
Pattern 5: The Self Parameter Explained
Memory model:
Loading Python environment...
Key insight: self = "the specific object this method is operating on"
Common Mistakes and Fixes
Mistake 1: Forgetting self in methods
Loading Python environment...
Mistake 2: Not calling constructor
Loading Python environment...
Mistake 3: Forgetting self. when accessing attributes
Loading Python environment...
Testing Pattern: Verify Independence
Always test that objects are independent:
Loading Python environment...
### Validation with AI
Once your patterns are complete, validate them:
> "Review my class design patterns. Are my explanations of self and object independence accurate? What patterns am I missing? What common mistakes should I add?"
**Deliverable**: Complete `class_design_patterns.md` with patterns and quick reference guide.
---
## Try With AI
Ready to master class syntax and understand how objects manage independent state?
**🔍 Explore Task Methods:**
> "Show me a Task class with title, priority, and due_date attributes. Add methods: mark_complete(), delay_deadline(days), and get_status(). Create three task objects with different priorities. When I call task1.mark_complete(), show step-by-step what happens in memory. How does Python know to modify only task1 and not task2?"
**🎯 Practice Domain Transfer:**
> "I'm building [describe your system: legal case management, invoice processing, appointment scheduling, etc.]. Help me design one core entity class. Walk me through: what attributes describe it? What methods represent key operations? How would I initialize multiple objects and modify them independently? Show code with test examples."
**🧪 Test Object Independence:**
> "Create a Case class with case_number, status, and client_name attributes. Add methods: close_case() and assign_attorney(attorney). Make three case objects. Close the first case and change its attorney. Show that the other two cases are unaffected. Why are they independent?"
**🚀 Apply Pattern Across Domains:**
> "I've learned Task classes with methods. Show me how the same pattern applies to: Invoice (with mark_paid() and apply_discount()), Appointment (with confirm() and reschedule()), and Product (with adjust_price() and restock()). How is the pattern universal across domains?"
---