← Previous Module 9: Inheritance & Polymorphism Next →
Statement
Solution

Python Exercise 9.2: Library Management

Put your OOP skills to work on a real-world system. Build a mini library that tracks books, members, and borrowing — using multiple classes that interact with each other.

Define three classes:

  • Book — stores title, author, and an is_available flag (default True). Has a __str__ method.
  • Member — stores name and a borrowed_books list (default empty). Has a borrow(book) method that marks the book unavailable and appends it to the member's list, rejecting if the book is already borrowed. Has a return_book(book) method that marks it available again and removes it from the list.
  • Library — stores a books list. Has add_book(book), show_available() (prints all available books), and show_all() (prints every book with its status).

Sample Interaction:

Input
Output
(None)
--- Available Books --- "1984" by George Orwell "Dune" by Frank Herbert "Sapiens" by Yuval Noah Harari Alice borrows "1984"... Alice borrows "Dune"... Bob tries to borrow "1984"... Error: "1984" is not available. --- Available Books --- "Sapiens" by Yuval Noah Harari Alice returns "1984"... --- All Books --- "1984" by George Orwell [Available] "Dune" by Frank Herbert [Borrowed] "Sapiens" by Yuval Noah Harari [Available]

Solution

Each class has a single, clear responsibility. Library manages the catalogue; Member manages borrowing state; Book tracks its own availability.

class Book: def __init__(self, title, author): self.title = title self.author = author self.is_available = True def __str__(self): return f'"{self.title}" by {self.author}' class Member: def __init__(self, name): self.name = name self.borrowed_books = [] def borrow(self, book): if not book.is_available: print(f'Error: "{book.title}" is not available.') return book.is_available = False self.borrowed_books.append(book) print(f'{self.name} borrows "{book.title}"...') def return_book(self, book): if book in self.borrowed_books: book.is_available = True self.borrowed_books.remove(book) print(f'{self.name} returns "{book.title}"...') class Library: def __init__(self): self.books = [] def add_book(self, book): self.books.append(book) def show_available(self): print("--- Available Books ---") for book in self.books: if book.is_available: print(book) def show_all(self): print("--- All Books ---") for book in self.books: status = "Available" if book.is_available else "Borrowed" print(f"{book} [{status}]") # Demo b1 = Book("1984", "George Orwell") b2 = Book("Dune", "Frank Herbert") b3 = Book("Sapiens", "Yuval Noah Harari") lib = Library() lib.add_book(b1) lib.add_book(b2) lib.add_book(b3) alice = Member("Alice") bob = Member("Bob") lib.show_available() print() alice.borrow(b1) alice.borrow(b2) bob.borrow(b1) # should fail print() lib.show_available() print() alice.return_book(b1) print() lib.show_all()

Key Concepts:

  • CompositionLibrary holds a list of Book objects; Member holds a list of borrowed Book objects. Classes work together without inheriting from each other.
  • Mutating an object's attribute (book.is_available = False) inside one class is immediately visible to all other classes holding a reference to the same object.
  • Guard clauses keep methods short and readable — check for error conditions first and return early.
  • list.remove(item) removes the first matching object from a list.
  • The in operator works on lists of objects, checking by identity/equality.
Python 3
Test Console
Run code to see output...

Go Beyond Learning. Get Job-Ready.

Build in-demand skills for today's jobs with free expert-led courses and practical AI tools.

Explore All Courses
Scroll to Top