4
\$\begingroup\$

Hi I just finished a VERY Basic airline reservation system. Wanted some feedback please let me know what you all think, if I am obfuscating information or passing parameters where I shouldn't or if things don't make sense

Airline Class: handles booking and refunds
Passenger: Has a seat assignment, and a balance to pay for ticket
Seat:
Firstclass and Coach
Plane:
a dictionary object holding seats and passengers get passed as values to those seats

here is my code:

class Airline:

    def __init__(self, name=None):
        self._name = name
        self._booked = []

    def get_name(self):
        return self._name

    def set_name(self, name):
        self._name = name

    def book(self, passenger, plane, cls=None):
        while cls not in ['first class', 'coach']:

            cls = input("Please pick a seat: First class or Coach ").lower()

            if cls not in ['first class', 'coach']:
                print("Please select either from 'first class' or 'coach'")
                pass
        if cls == 'first class':
            first_class = ([(number, seat) for number, seat in enumerate(plane.capacity)][0:10])
            choice = None
            while choice not in range(10):
                try:
                    choice = int(input(f"Please select a number between 0 and 9 for your seats: "))
                except ValueError:
                    print("Please select a valid number between 0 and 9")
                if choice in self._booked:
                    print(f"That seat is taken please choose another seat\n"
                          f"These seats are booked: {self._booked}")
                    choice = None
            for seat in first_class:
                if seat[0] == choice:
                    plane.capacity[seat[1]] = passenger
                    passenger._balance = passenger._balance - seat[1].price
                    self._booked.append(seat[0])
                    passenger._assignment = seat[1].tier + f" seat {seat[0]}"
        else:
            coach = ([(number, seat) for number, seat in enumerate(plane.capacity)][10:50])
            choice = None
            while choice not in range(10, 50):
                try:
                    choice = int(input(f"Please select a number between 10 and 50 for your seats: "))
                except ValueError:
                    print("Please select a valid number between 10 and 50")
                if choice in self._booked:
                    print(f"That seat is taken please choose another seat\n"
                          f"These seats are booked: {self._booked}")
                    choice = None
            for seat in coach:
                if seat[0] == choice:
                    plane.capacity[seat[1]] = passenger
                    passenger._balance = passenger._balance - seat[1].price
                    self._booked.append(seat[0])
                    passenger._assignment = seat[1].tier + f" seat {seat[0]}"

    def refund(self, passenger, plane):
        for i, (seat, person) in enumerate(plane.capacity.items()):
            if person == passenger:
                plane.capacity[seat] = None
                passenger._balance = passenger._balance + seat.price
                passenger._assignment = None
                self._booked.remove(i)


class Passenger:

    def __init__(self, balance=1000, assignment=None):
        self._balance = balance
        self._assignment = assignment

    def get_balance(self):
        return self._balance

    def get_assignment(self):
        return self._assignment


class Seat:

    def __init__(self):
        pass


class FirstClass(Seat):

    def __init__(self):
        super().__init__()
        self.tier = 'First Class'
        self.price = 500


class Coach(Seat):

    def __init__(self):
        super().__init__()
        self.tier = 'Coach'
        self.price = 100


class Plane:

    def __init__(self):
        self.capacity = {}
        temp_capacity = []  # Create a temporary list to append seats into ( this will be the seats in the airplane)
        for i in range(10):  # first 10 seats are first class
            temp_capacity.append(FirstClass())
        for i in range(10, 50):  # last 40 seats are coach class
            temp_capacity.append(Coach())
        for seat in temp_capacity:
            self.capacity[seat] = None  # Each seat has no value(person) assigned

    def view_plane(self):
        for i, k in self.capacity.items():
            print(f"{i} : {k}")

    def get_available_seats(self):
        count = 0
        for value in self.capacity.values():
            if value is None:
                count += 1
        return count

Running this below: (Will output how I envisioned the plane to be built and how seats are assigned to passengers, etc.)

plane = Plane()  
p = Passenger()  
p2 = Passenger()  
p3 = Passenger()  
airline = Airline()  

plane.view_plane()  
airline.book(p, plane)  
airline.book(p2, plane)  
print(airline._booked)  
print(f"passenger 1 balance: {p.get_balance()}\n"  
      f"passenger 1 assignment: {p.get_assignment()}\n"  
      f"passenger 2 balance: {p2.get_balance()}\n"  
      f"passenger 2 assignment: {p2.get_assignment()}\n"  
      f"Number of seats available: {plane.get_available_seats()}\n"  
      f"Number of seats booked: {len(airline._booked)}")  
plane.view_plane()  
airline.book(p3, plane)  
plane.view_plane()  
print("--------------")  
print(airline._booked)  
print(f"passenger 1 balance: {p.get_balance()}\n"  
      f"passenger 1 assignment: {p.get_assignment()}\n"  
      f"passenger 2 balance: {p2.get_balance()}\n"  
      f"passenger 2 assignment: {p2.get_assignment()}\n"  
      f"passenger 3 balance: {p3.get_balance()}\n"  
      f"passenger 3 assignment: {p3.get_assignment()}\n"  
      f"Number of seats available: {plane.get_available_seats()}\n"  
      f"Number of seats booked: {len(airline._booked)}")  
print("----------------")  
airline.refund(p2, plane)  
print(airline._booked)  
print(f"passenger 1 balance: {p.get_balance()}\n"  
      f"passenger 1 assignment: {p.get_assignment()}\n"  
      f"passenger 2 balance: {p2.get_balance()}\n"  
      f"passenger 2 assignment: {p2.get_assignment()}\n"  
      f"passenger 3 balance: {p3.get_balance()}\n"  
      f"passenger 3 assignment: {p3.get_assignment()}\n"  
      f"Number of seats available: {plane.get_available_seats()}\n"  
      f"Number of seats booked: {len(airline._booked)}")  

Please let me know better ways to do this or better interfaces etc. I will be slowly adding more complexity but my main goal was having the airline be able to book and place passengers in the plane and refund them from their seat while updating the planes capacity during these changes.

Will be adding multiple planes per airline which will undoubtedly change the structure of some of the classes but for right now let me know if what I have allows for the basic booking and refunding operations to work efficiently and if the classes are setup properly or what improvements can be made.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nicely written code, very easy to follow. Good job \$\endgroup\$ – Aryan Parekh Oct 8 '20 at 12:33
3
\$\begingroup\$

Nice implementation, it's easy to understand and well structured. Few suggestions:

Seat class

class Seat:
    def __init__(self):
        pass

class FirstClass(Seat):
    def __init__(self):
        super().__init__()
        self.tier = 'First Class'
        self.price = 500

class Coach(Seat):
    def __init__(self):
        super().__init__()
        self.tier = 'Coach'
        self.price = 100

A Seat is supposed to have a tier and a price, but this information is not in the main class, only in the subclasses.

Consider to add tier and price in the Seat constructor. I also suggest to add a number for the Seat class.

Typically, the price of the seat is not bound to a tier forever. The price of a seat depends on the flight. For example, the same seat can have two different prices for two flights on the same day. Consider this when you will expand the design.

Passenger class

class Passenger:

    def __init__(self, balance=1000, assignment=None):
        self._balance = balance
        self._assignment = assignment
  • A passenger should have at least a name, but most importantly an id.
  • I am not sure why you use underscore variables here. Is because they are for internal use? But the class Airline uses them in the book method like passenger._balance = ... Also the class Seat does not use underscore variables so I am a bit confused. Consider to use them consistently.

Book method

  • if choice in self._booked: here _booked is a list that contains all the reserved seats for all the planes. What happens if there is a reservation for the same seat number of two different planes? Consider to associate the reservations to a plane or better to a flight.
  • Performance: at every reservation, a new first_class is created:
    if cls == 'first class':
        first_class = ([(number, seat) for number, seat in enumerate(plane.capacity)][0:10])
    
    This is an expensive operation that can be avoided. Consider to create the first class in the plane and then request the result with a method.
  • Magic numbers and duplication:
    if cls == 'first class':
      first_class = ([(number, seat) for number, seat in enumerate(plane.capacity)][0:10])
      choice = None
      while choice not in range(10):
        try:
          choice = int(input(f"Please select a number between 0 and 9 for your seats: "))
      #...
    else:
      coach = ([(number, seat) for number, seat in enumerate(plane.capacity)][10:50])
      choice = None
      while choice not in range(10, 50):
        try:
          choice = int(input(f"Please select a number between 10 and 50 for your seats: "))
      #...
    
    The code to ask the user about tier and seat number is duplicated and there are some "magic numbers" like while choice not in range(10). In this case 10 is the number of seats in the first class of the given plane. I think it should be a property of the plane that has a first class with a certain number of seats. You can consider something like this:
    tier = plane.get_tier(cls) # tier is first class or coach
    choice = None
    while choice not in tier.get_seats_range():
      try:
        choice = int(input(f"Please select a number between {tier.get_seats_range()[0]} and {tier.get_seats_range()[1]} for your seats: ")) 
    
\$\endgroup\$
1
\$\begingroup\$

Here is some minor things on the class Airline

class Airline:

    def __init__(self, name=None):
        self._name = name
        self._booked = []

    def get_name(self):
        return self._name

    def set_name(self, name):
        self._name = name

Is strange to me that you can have an airline that have no name, so I would recommend to make the argument name mandatory. Conceptually is more correct from my point of view.

The other thing is that in python there is no concept of getters and setters, instead of that there is properties.

class Airline:

    def __init__(self, name):
        self._name = name
        self._booked = []

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.