
Python OOP Project: Hotel Booking System
Welcome to another hands-on Python tutorial! Today, we're building a Hotel Booking System using Object-Oriented Programming (OOP) principles. This project will help you practice key OOP concepts like classes, inheritance, encapsulation, and more. By the end, you'll have a functional system to manage rooms, guests, and bookings.
Let's start by defining our core classes: Room, Guest, and Booking. These will form the foundation of our system.
class Room:
def __init__(self, number, room_type, price_per_night):
self.number = number
self.type = room_type
self.price = price_per_night
self.is_booked = False
def book(self):
if not self.is_booked:
self.is_booked = True
return True
return False
def release(self):
self.is_booked = False
def __str__(self):
status = "Booked" if self.is_booked else "Available"
return f"Room {self.number} ({self.type}): ${self.price}/night - {status}"
Next, we'll create the Guest class to store information about our customers.
class Guest:
def __init__(self, name, email, phone):
self.name = name
self.email = email
self.phone = phone
def __str__(self):
return f"Guest: {self.name}, Email: {self.email}, Phone: {self.phone}"
Now, let's create the Booking class that will link rooms and guests together.
class Booking:
def __init__(self, guest, room, check_in, check_out):
self.guest = guest
self.room = room
self.check_in = check_in
self.check_out = check_out
self.total_cost = self.calculate_cost()
def calculate_cost(self):
nights = (self.check_out - self.check_in).days
return nights * self.room.price
def __str__(self):
return f"Booking: {self.guest.name} in Room {self.room.number} from {self.check_in} to {self.check_out}. Total: ${self.total_cost}"
To manage all these components, we'll create a Hotel class that acts as our main system controller.
class Hotel:
def __init__(self, name):
self.name = name
self.rooms = []
self.bookings = []
def add_room(self, room):
self.rooms.append(room)
def find_available_rooms(self, room_type=None):
available = [room for room in self.rooms if not room.is_booked]
if room_type:
available = [room for room in available if room.type == room_type]
return available
def book_room(self, guest, room_number, check_in, check_out):
room = next((r for r in self.rooms if r.number == room_number), None)
if not room or room.is_booked:
return None
if room.book():
booking = Booking(guest, room, check_in, check_out)
self.bookings.append(booking)
return booking
return None
def check_out(self, room_number):
room = next((r for r in self.rooms if r.number == room_number), None)
if room and room.is_booked:
room.release()
return True
return False
def list_bookings(self):
return self.bookings
Now let's see our system in action with a practical example.
from datetime import datetime, timedelta
# Create hotel
hotel = Hotel("Python Paradise Resort")
# Add some rooms
hotel.add_room(Room(101, "Single", 100))
hotel.add_room(Room(102, "Double", 150))
hotel.add_room(Room(103, "Suite", 300))
# Create a guest
guest1 = Guest("Alice Johnson", "alice@email.com", "555-1234")
# Book a room
check_in = datetime(2023, 12, 15)
check_out = datetime(2023, 12, 20)
booking = hotel.book_room(guest1, 102, check_in, check_out)
if booking:
print("Booking successful!")
print(booking)
else:
print("Room not available.")
# Show available rooms
print("\nAvailable rooms:")
for room in hotel.find_available_rooms():
print(room)
This basic implementation gives you a functional hotel booking system. You can extend it with features like payment processing, room services, or even a web interface.
Room Number | Type | Price/Night | Availability |
---|---|---|---|
101 | Single | $100 | Available |
102 | Double | $150 | Booked |
103 | Suite | $300 | Available |
Now let's enhance our system with some additional features. We'll add room maintenance tracking and special room types using inheritance.
class MaintenanceMixin:
def __init__(self):
self.needs_maintenance = False
def report_issue(self):
self.needs_maintenance = True
def fix_issue(self):
self.needs_maintenance = False
class PremiumRoom(Room, MaintenanceMixin):
def __init__(self, number, room_type, price_per_night, amenities):
super().__init__(number, room_type, price_per_night)
MaintenanceMixin.__init__(self)
self.amenities = amenities
def __str__(self):
status = "Booked" if self.is_booked else "Available"
maintenance = " - Needs Maintenance" if self.needs_maintenance else ""
return f"Room {self.number} ({self.type}): ${self.price}/night - {status}{maintenance}"
Let's also implement a simple payment system to make our booking process more complete.
class Payment:
def __init__(self, booking, amount, method="credit card"):
self.booking = booking
self.amount = amount
self.method = method
self.paid = False
self.payment_date = None
def process_payment(self):
# Simulate payment processing
self.paid = True
self.payment_date = datetime.now()
return True
def __str__(self):
status = "Paid" if self.paid else "Pending"
return f"Payment for Booking #{id(self.booking)}: ${self.amount} ({self.method}) - {status}"
Here's how we can integrate payments into our hotel system:
# Enhanced Hotel class with payment processing
class EnhancedHotel(Hotel):
def __init__(self, name):
super().__init__(name)
self.payments = []
def process_booking_payment(self, booking, payment_method="credit card"):
payment = Payment(booking, booking.total_cost, payment_method)
if payment.process_payment():
self.payments.append(payment)
return payment
return None
def get_revenue_report(self):
total = sum(p.amount for p in self.payments if p.paid)
return f"Total Revenue: ${total}"
- Create room inventory with different types and prices
- Implement guest registration and profile management
- Handle booking creation with date validation
- Process payments and generate receipts
- Manage room maintenance and availability
- Generate reports on occupancy and revenue
Let's create a more comprehensive example showing these features working together:
# Create enhanced hotel
enhanced_hotel = EnhancedHotel("Luxury Python Resort")
# Add various room types
enhanced_hotel.add_room(PremiumRoom(201, "Deluxe", 250, ["minibar", "jacuzzi"]))
enhanced_hotel.add_room(Room(202, "Standard", 120))
enhanced_hotel.add_room(PremiumRoom(203, "Presidential", 500, ["butler", "private pool"]))
# Create guests
guest2 = Guest("Bob Smith", "bob@email.com", "555-5678")
guest3 = Guest("Carol Davis", "carol@email.com", "555-9012")
# Make bookings
booking2 = enhanced_hotel.book_room(guest2, 201, datetime(2023, 12, 18), datetime(2023, 12, 22))
booking3 = enhanced_hotel.book_room(guest3, 202, datetime(2023, 12, 20), datetime(2023, 12, 25))
# Process payments
if booking2:
payment2 = enhanced_hotel.process_booking_payment(booking2)
print(f"Payment processed: {payment2}")
if booking3:
payment3 = enhanced_hotel.process_booking_payment(booking3, "debit card")
print(f"Payment processed: {payment3}")
# Generate revenue report
print(enhanced_hotel.get_revenue_report())
Room Type | Average Price | Occupancy Rate | Revenue Contribution |
---|---|---|---|
Standard | $120 | 75% | 30% |
Deluxe | $250 | 60% | 40% |
Presidential | $500 | 40% | 30% |
Now let's implement some error handling and input validation to make our system more robust:
class BookingError(Exception):
pass
class InvalidDateError(BookingError):
pass
class RoomUnavailableError(BookingError):
pass
class EnhancedBookingSystem(EnhancedHotel):
def validate_booking_dates(self, check_in, check_out):
if check_out <= check_in:
raise InvalidDateError("Check-out date must be after check-in date")
if check_in < datetime.now():
raise InvalidDateError("Cannot book for past dates")
def book_room(self, guest, room_number, check_in, check_out):
try:
self.validate_booking_dates(check_in, check_out)
room = next((r for r in self.rooms if r.number == room_number), None)
if not room:
raise ValueError("Room not found")
if room.is_booked:
raise RoomUnavailableError(f"Room {room_number} is already booked")
if room.needs_maintenance if hasattr(room, 'needs_maintenance') else False:
raise RoomUnavailableError(f"Room {room_number} is under maintenance")
if room.book():
booking = Booking(guest, room, check_in, check_out)
self.bookings.append(booking)
return booking
except (InvalidDateError, RoomUnavailableError, ValueError) as e:
print(f"Booking failed: {e}")
return None
Let's test our error handling with some edge cases:
# Test error handling
try:
# Past date booking
past_booking = enhanced_hotel.book_room(
guest2, 202,
datetime(2022, 1, 1),
datetime(2022, 1, 5)
)
# Invalid date range
invalid_dates = enhanced_hotel.book_room(
guest3, 203,
datetime(2023, 12, 25),
datetime(2023, 12, 20)
)
except Exception as e:
print(f"Error: {e}")
# Try to book already booked room
duplicate_booking = enhanced_hotel.book_room(
guest1, 201,
datetime(2023, 12, 25),
datetime(2023, 12, 30)
)
Finally, let's add some reporting functionality to help hotel management make data-driven decisions:
class HotelAnalytics:
def __init__(self, hotel):
self.hotel = hotel
def occupancy_rate(self):
total_rooms = len(self.hotel.rooms)
booked_rooms = sum(1 for room in self.hotel.rooms if room.is_booked)
return (booked_rooms / total_rooms) * 100 if total_rooms > 0 else 0
def average_stay_length(self):
if not self.hotel.bookings:
return 0
total_nights = sum((b.check_out - b.check_in).days for b in self.hotel.bookings)
return total_nights / len(self.hotel.bookings)
def revenue_by_room_type(self):
revenue = {}
for payment in self.hotel.payments:
if payment.paid:
room_type = payment.booking.room.type
revenue[room_type] = revenue.get(room_type, 0) + payment.amount
return revenue
# Usage
analytics = HotelAnalytics(enhanced_hotel)
print(f"Occupancy Rate: {analytics.occupancy_rate():.1f}%")
print(f"Average Stay: {analytics.average_stay_length():.1f} nights")
print("Revenue by Room Type:", analytics.revenue_by_room_type())
- Start with simple classes and gradually add complexity
- Use inheritance for specialized room types and features
- Implement proper error handling for robust operation
- Add analytics to track business performance
- Consider using databases for persistent storage in real applications
- Implement user authentication for multi-user access
- Add reservation modification and cancellation features
This hotel booking system demonstrates how object-oriented programming can help you create organized, maintainable code for complex real-world applications. Each class has a clear responsibility, and the relationships between them model the actual hotel operations.
Remember that this is a simplified version. In a production system, you'd want to add features like database persistence, user authentication, a web interface, and more comprehensive error handling. However, this foundation gives you all the core concepts you need to build upon.
Keep coding and enhancing this system – try adding features like room service orders, housekeeping management, or integration with payment gateways. The possibilities are endless when you have a solid OOP foundation!