GuideIntermediate
Python Oop And Data Modeling
A plain dictionary with the right keys can look like an object, but it doesn't protect its invariants, doesn't expose behavior, and breaks silently the moment someone puts an invalid value in it. This guide teaches you to design a clean, correct, "Pythonic" object model starting from that exact problem. You work by modeling a single domain end to end — Reservo, a coworking room-booking system — and build it with classes from scratch: first the move from loose data to an object that bundles data and behavior, then encapsulation with properties that validate invariants, `@dataclass` for modeling immutable data without boilerplate, composition to assemble the domain's object graph, inheritance and polymorphism for the different member types, protocols and abstract classes to design against interfaces instead of concrete implementations, and the dunder methods that make an object feel native to Python (comparison, ordering, iteration, context managers). All the code actually runs on Python 3.14 and is checked against anchor numbers from the domain (a 3-hour booking in the Focus room costs 7500 cents, with a 20% discount for the pro tier). The final project models the complete Reservo domain with all eight pieces integrated and a runnable demo.
- 64
- lessons
- 8
- modules
- English · Spanish
- available in
- Included in the Club
- access
Outcomes
What you'll be able to do
- Move from loose data (dictionaries, tuples) to your own class, understanding the difference between class and instance, `__init__`, and `self`
- Encapsulate state with `@property` to expose behavior without breaking invariants, validating domain rules (`capacity > 0`, non-negative prices) in the right place
- Model data with `@dataclass`, including immutable value objects with `frozen=True` and validation with `__post_init__`
- Choose with judgment between composition and inheritance ("has-a" versus "is-a") and model the object graph of a real domain
- Apply inheritance and polymorphism so different types of the same concept (membership tiers, for example) compute different behavior behind the same interface
- Design against interfaces with `typing.Protocol` (structural typing, duck typing) and with abstract classes (`abc.ABC`) when a nominal interface is needed
- Implement dunder methods (`__repr__`, `__eq__`, `__hash__`, `__lt__`, `__len__`, `__iter__`, `__contains__`) so an object behaves like a native Python type
- Build custom context managers with `__enter__` and `__exit__`
- Distinguish when to use a plain class, a dataclass, or a protocol based on what the domain needs to express
- Integrate an entire real domain's model — entities, collections, orchestrating service — into a runnable, verifiable system
Before you start
What you need to bring
It's for you if...
- Intermediate-level Python developers who write code with loose functions and dictionaries and want to move to real object-oriented design
- Devs who use classes mechanically but never had a clear framework for choosing between composition and inheritance
- People who want to understand `@dataclass`, `Protocol`, and dunder methods beyond copying isolated examples from the internet
- Anyone preparing technical interviews where they're asked about object-oriented design, applied SOLID principles, or when to prefer composition over inheritance
- Anyone moving on to the sibling packaging or testing guides who first needs a well-designed domain model to work on
Requirements and materials
- Basic Python syntax: variables, functions, control flow, data structures
- Minimal notions of classes (you don't need to have designed a serious object model before)
- Python 3.14 installed; all the code runs with the standard library, no external dependencies
- No need to know database design, testing with pytest, or packaging: those topics live in their own guides
Content
The syllabus, module by module
Open any of them to see its lessons.
- 1. Introduction: From data to objects
- 2. Why OOP — from a bare dict to an object
- 3. What a class is vs an instance
- 4. `__init__` and `self`
- 5. Instance attributes
- 6. The first method — behavior over state
- 7. Multiple instances and their identity
- 8. Mini-project: model a `Room`
- 1. Module introduction: the object that looks after itself
- 2. Attributes vs methods: the object as guardian
- 3. The underscore convention
- 4. `@property` as a computed getter
- 5. Setters that validate
- 6. Invariants in `__init__` with `ValueError`
- 7. Why encapsulate: the always-valid object
- 8. Mini-project: a self-validating `Member`
- 1. Module introduction: stop writing boilerplate
- 2. The boilerplate and what `@dataclass` generates
- 3. Declaring fields with types
- 4. Defaults and the mutable default trap
- 5. `frozen=True` and immutable value objects
- 6. Validating with `__post_init__`
- 7. Dataclass vs regular class
- 8. Mini-project: `Booking` as a value object
- 1. Module introduction: the object graph
- 2. "Has-a" versus "is-a": the key distinction
- 3. Association: a `Booking` references a `Room` and a `Member`
- 4. Composition: a `BookingService` has a `Calendar`
- 5. Aggregation versus composition: the lifecycle
- 6. Delegation: forwarding the work to a collaborator
- 7. Preferring composition over inheritance, and why
- 8. Mini-project: the booking service and its calendar
- 1. Introduction to Inheritance and Polymorphism
- 2. Inheritance — Base Class and Subclass
- 3. `super()` and Extending the Constructor
- 4. Overriding Methods
- 5. Polymorphism — Same Call, Different Behavior
- 6. When Inheritance Helps and When It Hurts
- 7. A Note on Multiple Inheritance and MRO
- 8. Mini-Project — Member Tiers with Polymorphism
- 1. Introduction to Protocols and Duck Typing
- 2. Duck Typing — The Methods Matter, Not the Class
- 3. `typing.Protocol` — The Structural Interface
- 4. A Domain Interface — `Repository` and `Clock`
- 5. ABC with `@abstractmethod` — The Nominal Interface
- 6. Protocol vs ABC — Structural vs Nominal
- 7. Designing Against the Interface Decouples
- 8. Mini-Project: a `Repository` Protocol for Bookings
- 1. Introduction to Dunder Methods and Pythonic Objects
- 2. `__repr__` vs `__str__`: Two Ways to Look
- 3. Value Equality: `__eq__` and `__hash__`
- 4. Ordering: `__lt__` and `functools.total_ordering`
- 5. The Container Protocol: `__len__`, `__contains__`, `__getitem__`
- 6. Making `Calendar` Iterable with `__iter__`
- 7. Context Managers: `__enter__` and `__exit__`
- 8. Mini-Project: a Pythonic `Calendar`
- 1. Introduction: Model the Reservo Domain
- 2. `Room` with Invariants
- 3. `Member` with Polymorphic Tiers
- 4. `Booking` as a Frozen Dataclass
- 5. `Calendar` with Dunders
- 6. The `BookingService` That Composes and Orchestrates
- 7. Protocols at the Boundaries
- 8. Project: Model the Reservo Domain
Where it fits
This guide is part of something bigger
It's studied inside these programs, with support and dates.
Common questions
What people usually ask
As long as your Club subscription is active. If you cancel and come back later, you get the access and your progress back.
No. Modules run from easier to harder, but you can jump to the one you need. Progress is saved per lesson.
Whatever is needed is listed under “What you need to bring”, above. If nothing is listed there, you can start from zero.
In the Club's WhatsApp group, and every two weeks there's a live with an instructor where questions get worked through.
No. This guide is self-paced with no dates. The bootcamp is live, by cohort, with work someone reviews.
Start whenever you like
What students say
These reviews are from enrolled students who completed at least 50% of the course. We moderate reviews only on content grounds (spam, offensive language, personal data), never for being critical or negative.
No approved reviews yet.
Be the first to share your experience!