Skip to main content

Chapter 61: Decorators, Properties, and Advanced Patterns

James opens the Note class from Chapter 60. It displays itself, compares itself, iterates, hashes. It is Pythonic. But one thing bothers him: word_count is a stored field. Every time he edits the body, the count goes stale. He changed the body last session and forgot to update word_count. The object lied to him.

"The count should compute itself," Emma says. "You should not have to remember to update it. That is what @property does: it makes a method look like an attribute. You access note.word_count, and Python runs the computation behind the scenes."

This chapter teaches the final set of OOP patterns for Phase 5. You will add @property for computed attributes, @staticmethod and @classmethod for organizing class functionality, custom decorators for cross-cutting behavior, and Protocol for defining interfaces without inheritance. Every concept connects to the SmartNotes project, and every lesson uses the same TDG cycle you mastered in Phase 4.

What You Will Learn

By the end of this chapter, you will be able to:

  • Use @property to replace stored fields with computed values that stay synchronized with the object's state
  • Choose between @staticmethod (utility functions) and @classmethod (alternative constructors) and place each appropriately in a class
  • Write custom decorators that modify function behavior, and use functools.wraps to preserve function metadata
  • Define a Protocol for structural subtyping and explain how it differs from ABC for dependency injection and testing
  • Combine all Phase 5 patterns in a capstone TDG cycle: Repository Protocol, @validate_input decorator, computed properties, and factory methods

Chapter Lessons

LessonTitleWhat You DoDuration
1Properties: Computed AttributesReplace stored word_count with @property that computes from self.body. Learn getters, setters, and why properties keep interfaces stable.20 min
2Static Methods and Class MethodsMove note_from_dict() onto the Note class as Note.from_dict() using @classmethod. Organize utility functions with @staticmethod.15 min
3Custom DecoratorsWrite @log_calls and @validate_input decorators. Understand that @decorator is func = decorator(func). Use functools.wraps.20 min
4Protocols: Structural SubtypingDefine a Repository Protocol with save() and find_by_id(). Write InMemoryRepository that satisfies the Protocol without inheriting from it. Compare Protocol vs ABC.20 min
5SmartNotes Advanced Patterns CapstoneCombine all Phase 5 patterns in one TDG cycle: Repository Protocol, @validate_input, @property, Note.from_dict(). All tests pass.25 min
6Chapter 61 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 with decorators, properties, and protocols.

StageWhat You DoClaude Code Tool
Predict [AI-FREE]Predict what @property returns, what @classmethod receives as its first argument, or whether a class satisfies a Protocol. 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 property behavior. Compare results to your prediction.You run it, not Claude Code
InvestigateRead test output or property behavior to understand why a prediction was wrong. In Claude Code, type: /investigate for Socratic questions about decorators and protocols./investigate probes mechanics
ModifyRefine a property, fix a decorator, or update a class to satisfy a Protocol. Predict whether the change resolves the issue.You edit, Claude Code reviews
Make [Mastery Gate]Build the SmartNotes advanced architecture with all patterns 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:

  • Build a Python class with __init__, typed methods, and instance attributes (Chapter 58)
  • Choose between inheritance and composition using the design decision framework (Chapter 59)
  • Implement special methods (__repr__, __eq__, __iter__, __len__, __contains__, __hash__) for Pythonic objects (Chapter 60)
  • Drive the full TDG cycle independently: specify, test, generate, verify, debug (Chapter 57)

The SmartNotes Connection

This chapter completes the SmartNotes object model. The Note class gains computed properties (word_count from @property), a factory method (Note.from_dict() via @classmethod), input validation (@validate_input decorator), and a testable storage interface (Repository Protocol with InMemoryRepository).

The five lessons build the final architecture:

  • Lesson 1 (Computation): Replace the stale word_count field with a live @property
  • Lesson 2 (Organization): Add Note.from_dict() as a @classmethod factory and organize utilities with @staticmethod
  • Lesson 3 (Cross-Cutting): Write @validate_input to guard methods across the class
  • Lesson 4 (Interfaces): Define a Repository Protocol so storage can be swapped without changing the class hierarchy
  • Lesson 5 (Capstone): Combine everything in one TDG cycle with full test coverage