Chapter 58: Classes and Instances
James opens SmartNotes and stares at the Note dataclass he has been using since Chapter 51. It stores title, body, and tags. It works. But now he needs add_tag() to reject duplicates, word_count to compute a value from the body, and summarize() to format output for the terminal. He keeps adding methods to the dataclass, and each one needs validation logic that @dataclass was never designed to handle. "The dataclass is doing too much," Emma says. "It started as a data container, and now it wants to be something with behavior. That is not a bug in your code. That is a signal that you need a class."
This chapter teaches you to build classes from scratch. You will learn the class statement, __init__, self, methods that read and modify state with validation, and the critical difference between instance attributes and class attributes. Every concept connects to the SmartNotes project, and every lesson uses the same TDG cycle you mastered in Phase 4.
The TDG connection: same cycle, but now you specify class interfaces instead of function signatures. "Specify" means defining a class with typed method signatures. "Test" means creating instances, calling methods, and asserting state changes. The loop is the same. The building blocks are bigger.
What You Will Learn
By the end of this chapter, you will be able to:
- Recognize when a dataclass outgrows its role as a data container and apply the decision framework (mostly data vs. significant behavior) to choose between dataclass and class
- Write a Python class with
__init__, typed parameters, and instance attributes usingself - Design methods that read state, modify state with validation, and query state
- Distinguish between instance attributes (unique per object) and class attributes (shared), and avoid the mutable class attribute trap
- Convert a dataclass to a full class using the TDG cycle with 12 tests
Chapter Lessons
| Lesson | Title | What You Do | Duration |
|---|---|---|---|
| 1 | The Dataclass Ceiling | Identify when a dataclass needs to become a full class. Apply the mostly-data vs. significant-behavior decision framework. | 20 min |
| 2 | The class Statement and init | Write a class from scratch with __init__, typed parameters, and self. Compare to the equivalent dataclass. | 20 min |
| 3 | Methods: Functions That Belong to Objects | Write methods that read state (.summarize()), modify state with validation (.add_tag()), and query state (.has_tag()). Test method behavior. | 20 min |
| 4 | Instance vs Class Attributes | Predict whether modifying one instance affects another. Find and fix the mutable class attribute trap. | 15 min |
| 5 | SmartNotes Class TDG | Convert @dataclass Note to class Note with validation, computed properties, and tag management. 12 tests. Full TDG cycle. | 25 min |
| 6 | Chapter 58 Quiz | 20 scenario-based questions covering all five lessons | 25 min |
PRIMM-AI+ in This Chapter
Every lesson includes a PRIMM-AI+ Practice section following the five-stage cycle from Chapter 42. This is Phase 5: the TDG cycle now specifies class interfaces instead of function signatures.
| Stage | What You Do | Claude Code Tool |
|---|---|---|
| Predict [AI-FREE] | Predict what self refers to, what a method returns, or whether modifying one instance affects another. Press Shift+Tab for Plan Mode. | Plan Mode protects prediction |
| Run | Press Shift+Tab to exit Plan Mode. Run uv run pyright on class stubs, uv run pytest on method tests, or uv run python to check attribute behavior. Compare results to your prediction. | You run it, not Claude Code |
| Investigate | Read test output or class behavior to understand why a prediction was wrong. In Claude Code, type: /investigate for Socratic questions about class mechanics. | /investigate probes mechanics |
| Modify | Refine a class definition, fix a method, or move a mutable attribute into __init__. Predict whether the change resolves the issue. | You edit, Claude Code reviews |
| Make [Mastery Gate] | Convert the SmartNotes dataclass to a full class with 12 tests using the TDG cycle. In Claude Code, type: /tdg for structured TDG workflows. | Your work, Claude Code guides |
Your PRIMM-AI+ starter kit from Chapter 42 works throughout Phase 5. Use /predict, /investigate, /bug, /debug, and /tdg commands as you work through each lesson.
Prerequisites
Before starting this chapter, you should be able to:
- Drive the full TDG cycle independently: specify, test, generate, verify, debug (Chapter 57)
- Write dataclasses with typed fields and defaults (Chapter 51)
- Write and run pytest tests using
uv run pytest(Chapters 46, 52) - Use
@pytest.mark.parametrizeand fixtures (Chapter 52) - Run the verification tools:
uv run ruff check,uv run pyright,uv run pytest(Chapters 52-56)
The SmartNotes Connection
This chapter transforms SmartNotes from a data-container design to an object-oriented design. The @dataclass Note you built in Chapter 51 becomes class Note with validated initialization, computed properties, and tag management methods.
The five lessons mirror the journey from dataclass to class:
- Lesson 1 (Decision): Recognize when the dataclass ceiling is reached and decide to convert
- Lesson 2 (Foundation): Write the class with
__init__andself, replacing@dataclassauto-generation - Lesson 3 (Behavior): Add methods that read, modify, and query instance state
- Lesson 4 (Scoping): Understand where attributes live and avoid shared-state traps
- Lesson 5 (Capstone): Convert the full SmartNotes Note using the TDG cycle with 12 tests