Chapter Summary

Chapter Summary

Key Points

  • 1.

    Use classes when state and behavior belong together. Functions are ideal for stateless transformations, but classes shine when you need to bundle configuration, internal buffers, and iteration history with algorithmic logic. The @dataclass decorator eliminates boilerplate for parameter containers like SimulationConfig β€” use frozen=True for immutability and slots=True for memory efficiency.

  • 2.

    ABCs enforce contracts; Protocols enable flexibility. Abstract base classes (abc.ABC with @abstractmethod) catch missing method implementations at instantiation time β€” a fail-fast guarantee valuable for long-running simulations. typing.Protocol provides structural subtyping (formalized duck typing) that works across library boundaries without forcing inheritance. Use ABCs for internal APIs you control; use Protocols for interfaces that third-party code must satisfy.

  • 3.

    NumPy's array protocols enable seamless interop. Implement __array__ for basic ndarray conversion, __array_ufunc__ to intercept element-wise operations (preserving units, types, or metadata), and __array_function__ for full NumPy API coverage. These protocols are how CuPy, JAX, and Dask provide NumPy-compatible interfaces. The __cuda_array_interface__ extends this pattern to zero-copy GPU data exchange.

  • 4.

    Composition beats inheritance for research flexibility. Deep inheritance hierarchies create combinatorial explosions (N solvers x M denoisers = N*M subclasses). Composition assembles independent components through protocols, giving N + M components that combine freely. The strategy pattern makes algorithms swappable; dependency injection makes code testable with mock objects.

  • 5.

    These patterns compose into production architectures. Dataclass configs feed into composed solvers that use protocol-based components. This architecture β€” seen in scikit-learn's estimator API, PyTorch's nn.Module, and SciPy's optimize interface β€” scales from research prototypes to production systems.

Looking Ahead

Chapter 4 moves from object design to iteration protocols and generators for scientific computing. You will learn to build memory-efficient data pipelines using __iter__/__next__, generator functions, and itertools β€” patterns that process datasets larger than memory and stream simulation results in real time.