The OOP System

Advanced · 90 min build · 🏆 milestone project

One object is easy. A system is where your design gets tested. Your goal is to build a library manager, a text-based program that tracks books, members, checkouts, due dates, and returns using classes that cooperate instead of one giant script.

You are practicing the Part III skill: think in objects. The finished system should use classes, inheritance, dunder methods, and at least one decorator, while also using regex for catalog IDs and datetime for due dates.

What you'll build

You will build one menu-driven library manager with these routes:

  • 1: list the catalog.
  • 2: check out an item to a member.
  • 3: return an item.
  • 4: show a short library summary.
  • 7: exit cleanly.

A catalog item is one thing the library can lend, such as a book or audiobook. A loan is the act of assigning an item to a member until a due date. The scaffold is starter code with TODO comments that show where your work belongs. The acceptance criteria are checks you can run yourself to prove each stage works.

The design picture is the house-blueprint idea from OOP: LibraryItem is the base blueprint, and Book and AudioBook are revised blueprints based on it. Library is the front desk that stores items and sends work to the right object.

python — playgroundlive
⌘/Ctrl + Enter to run

Checkpoint 1: the object model

Start by making the object blueprints honest. Keep data that belongs to one item inside LibraryItem, and keep catalog-wide behavior inside Library.

Acceptance criteria:

  • Creating Book("LIB-001", "Python Field Notes", "Ada Stone", 240) works.
  • Creating an item with "BAD-1" raises ValueError: catalog IDs must look like LIB-001.
  • item.is_available returns True before checkout.
  • str(item) shows the catalog ID, title, and status.
  • repr(item) gives a developer-facing representation that includes the class name.

Checkpoint 2: inheritance and dunder methods

Now make the subclasses earn their place. Book and AudioBook should share lending behavior from LibraryItem, then add their own details.

Acceptance criteria:

  • Book and AudioBook both inherit checkout() and return_item() from LibraryItem.
  • len(book) returns the page count.
  • len(audio_book) returns the minute count.
  • len(library) returns the number of catalog items.
  • "LIB-001" in library returns True when that item exists and False when it does not.

Checkpoint 3: checkout, return, and due dates

Build the lending behavior next. This is where objects start cooperating: the menu talks to Library, Library finds one item, and the item updates its own state.

Acceptance criteria:

  • Route 2 asks for catalog ID and member name.
  • Checking out an available item stores the member name.
  • The due date is TODAY + timedelta(days=LOAN_DAYS).
  • Trying to check out an unavailable item prints who already has it.
  • Route 3 clears checked_out_by and due_at.
  • The @log_action decorator runs after checkout and return.

Use the text and time tools from Section 13 where they belong. Regex should check catalog ID shape, and datetime should represent due dates.

Acceptance criteria:

  • find_by_id() returns the matching item object, not a string or dictionary.
  • Unknown catalog IDs print No item found for LIB-999. or the matching ID.
  • Catalog IDs are normalized with .strip().upper() before lookup.
  • Due dates are aware datetimes using ZoneInfo("Asia/Kolkata").
  • Listing the catalog after a checkout shows the changed status.

Checkpoint 5: test the full system

Walk every route like a user. A project is not done because one happy path worked.

Acceptance criteria:

  • Entering 7 prints Goodbye and exits.
  • Route 1 lists all demo items.
  • Route 4 shows item, available, and checked-out counts.
  • Checkout followed by catalog listing shows the item as unavailable.
  • Return followed by summary increases the available count.
  • The code has no giant route that edits every detail directly; objects own their own behavior.

Stretch goals

Choose one or two after the base system works:

  • Add a Member class with __str__ and a list of checked-out catalog IDs.
  • Add a DigitalBook subclass with a download size.
  • Add a route that lists overdue items by comparing due_at to a fixed aware datetime.
  • Save and load the catalog in JSON during one page session.
  • Add a custom class decorator that registers every item type by name.

How to get unstuck

If the class shape gets fuzzy, revisit Thinking in Objects and Classes & Instances. If subclass behavior feels duplicated, go back to Inheritance. If len(item), str(item), or "LIB-001" in library surprises you, rebuild the examples from Special Dunder Methods. If the decorator wrapper gets noisy, compare it to Decorators. If ID validation or due dates fail, return to Regular Expressions and Dates, Times & Time Zones.

Part III is complete when this project feels like a set of cooperating objects, not one long script. Part IV shifts the focus from building programs that work to shaping programs that stay readable, testable, and professional as they grow.

+50 XP on completion