Skip to main content

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 using self
  • 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

LessonTitleWhat You DoDuration
1The Dataclass CeilingIdentify when a dataclass needs to become a full class. Apply the mostly-data vs. significant-behavior decision framework.20 min
2The class Statement and initWrite a class from scratch with __init__, typed parameters, and self. Compare to the equivalent dataclass.20 min
3Methods: Functions That Belong to ObjectsWrite methods that read state (.summarize()), modify state with validation (.add_tag()), and query state (.has_tag()). Test method behavior.20 min
4Instance vs Class AttributesPredict whether modifying one instance affects another. Find and fix the mutable class attribute trap.15 min
5SmartNotes Class TDGConvert @dataclass Note to class Note with validation, computed properties, and tag management. 12 tests. Full TDG cycle.25 min
6Chapter 58 Quiz20 scenario-based questions covering all five lessons25 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.

StageWhat You DoClaude 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
RunPress 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
InvestigateRead 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
ModifyRefine 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
Starter Kit

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.parametrize and 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__ and self, replacing @dataclass auto-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