Day 41 to Day 50 python oops practice questions

Index: Click to Navigate:

Day41 

 Day 41

Question:

Write a Python class Employee with attributes name, emp_id, and department. Create objects for two employees and display their details.

Solution:

class Employee:

    def __init__(self, name, emp_id, department):

        self.name = name

        self.emp_id = emp_id

        self.department = department

   def display_details(self):

        print(f"Employee ID: {self.emp_id}, Name: {self.name}, Department:    

                 {self.department}")

emp1 = Employee("Ravi Kumar", 101, "HR")

emp2 = Employee("Sneha Reddy", 102, "IT")

emp1.display_details()

emp2.display_details()

Output:

Employee ID: 101, Name: Ravi Kumar, Department: HR

Employee ID: 102, Name: Sneha Reddy, Department: IT

Explanation:

1️⃣ Class Definition

class Employee:
  • The Employee class is defined using the class keyword.
  • This class represents an employee with attributes like name, emp_id, and department.

2️⃣ Constructor (__init__ method)

def __init__(self, name, emp_id, department):
    self.name = name
    self.emp_id = emp_id
    self.department = department
  • The __init__ method is the constructor in Python.
  • It gets called automatically when an object of the class is created.
  • It takes 3 parameters (name, emp_id, department) and initializes them using self.

🔹 self refers to the instance of the class and allows us to store values in instance variables (self.name, self.emp_id, self.department).

3️⃣ Method to Display Employee Details

def display_details(self):
    print(f"Employee ID: {self.emp_id}, Name: {self.name}, 
    Department: {self.department}")
  • This is a user-defined method that prints the employee details in a readable format.
  • It uses formatted strings (f"") to include variables inside the print statement.

4️⃣ Creating Employee Objects

emp1 = Employee("Ravi Kumar", 101, "HR")
emp2 = Employee("Sneha Reddy", 102, "IT")
  • Two employee objects (emp1 and emp2) are created by passing values to the Employee constructor.
  • The __init__ method initializes each object with the given details.

5️⃣ Displaying Employee Details

emp1.display_details()
emp2.display_details()
  • The display_details() method is called for both objects to print their information.

💡 Output Explanation

Employee ID: 101, Name: Ravi Kumar, Department: HR
Employee ID: 102, Name: Sneha Reddy, Department: IT
  • The first employee (Ravi Kumar) works in the HR department with ID 101.
  • The second employee (Sneha Reddy) works in the IT department with ID 102.

 Day 42

Question:

Design a BankAccount class with attributes account_holder and __balance. Implement methods to deposit money (only if the amount is positive) and withdraw money (only if sufficient balance is available, otherwise print "Insufficient funds!"). Display the account holder's name and balance.

Solution:

class BankAccount:

    def __init__(self, account_holder, balance=0):

        self.account_holder = account_holder

        self.__balance = balance  

    def deposit(self, amount):

        if amount > 0:

            self.__balance += amount

            print(f"{amount} deposited. New Balance: {self.__balance}")

        else:

            print("Deposit amount must be positive!")

    def withdraw(self, amount):

        if amount > self.__balance:

            print("Insufficient funds!")

        else:

            self.__balance -= amount

            print(f"{amount} withdrawn. Remaining Balance: {self.__balance}")

    def display_details(self):

        print(f"Account Holder: {self.account_holder}")

        print(f"Current Balance: {self.__balance}")

account = BankAccount("Ram", 5000)

account.display_details()

account.deposit(2000)

account.withdraw(3000)

Output:

Account Holder: Ram

Current Balance: 5000

2000 deposited. New Balance: 7000

3000 withdrawn. Remaining Balance: 4000

Explanation:

1. Class Definition and Constructor (__init__ Method)

class BankAccount:
    def __init__(self, account_holder, balance=0):
        self.account_holder = account_holder  # Public attribute
        self.__balance = balance  # Private attribute (Encapsulation)
  • The __init__ method initializes the object with two attributes:
    • account_holder: Stores the name of the account holder (public attribute).
    • __balance: Stores the account balance (private attribute to restrict direct access).
  • balance=0 provides a default value if no balance is provided.

2. Deposit Method (deposit())

def deposit(self, amount):
    if amount > 0:
        self.__balance += amount
        print(f"{amount} deposited. New Balance: {self.__balance}")
    else:
        print("Deposit amount must be positive!")
  • This method allows users to deposit money into their account.
  • If the deposit amount is positive, it adds the amount to __balance.
  • If the deposit amount is negative or zero, it prints an error message.

3. Withdraw Method (withdraw())

def withdraw(self, amount):
    if amount > self.__balance:
        print("Insufficient funds!")
    else:
        self.__balance -= amount
        print(f"{amount} withdrawn. Remaining Balance: {self.__balance}")
  • This method allows users to withdraw money.
  • If the requested amount is greater than the available balance, it prints "Insufficient funds!".
  • Otherwise, it deducts the amount from __balance and prints the new balance.

4. Display Method (display_details())

def display_details(self):
    print(f"Account Holder: {self.account_holder}")
    print(f"Current Balance: {self.__balance}")
  • This method prints the account holder's name and the current balance.

Creating an Object and Performing Operations

account = BankAccount("Ram", 5000)  # Creating an account with an initial 
                                                                       balance of 5000

account.display_details()  # Display initial details

account.deposit(2000)  # Depositing 2000
account.withdraw(3000)  # Withdrawing 3000

Step-by-Step Execution:

  1. Create an account for "Ram" with an initial balance of 5000.
  2. Display account details, showing:
    Account Holder: Ram
    Current Balance: 5000
    
  3. Deposit 2000 into the account, updating the balance to 7000:
    2000 deposited. New Balance: 7000
    
  4. Withdraw 3000, reducing the balance to 4000:
    3000 withdrawn. Remaining Balance: 4000
    

Day 43

Question:

Create a Vehicle class with attributes brand and year. Inherit it in a Car class with an additional attribute model. Display all details using a method.

Solution:

class Vehicle:

    def __init__(self, brand, year):

        self.brand = brand

        self.year = year

class Car(Vehicle):

    def __init__(self, brand, year, model):

        super().__init__(brand, year)

        self.model = model

     def display_info(self):

        print(f"Brand: {self.brand}\nYear: {self.year}\nModel: {self.model}")

car1 = Car("Honda", 2020, "Civic")

car1.display_info()

Output:

Brand: Honda

Year: 2020

Model: Civic

Explanation:

1️⃣ Vehicle Class (Parent Class)

class Vehicle:
    def __init__(self, brand, year):
        self.brand = brand
        self.year = year
  • Purpose: Represents a general vehicle.
  • Attributes:
    • brand → Stores the brand name (e.g., "Honda").
    • year → Stores the manufacturing year (e.g., 2020).
  • Constructor (__init__ method) initializes the brand and year when an object is created.

2️⃣ Car Class (Child Class) - Inherits from Vehicle

class Car(Vehicle):
    def __init__(self, brand, year, model):
        super().__init__(brand, year)  
        self.model = model
  • Inherits from Vehicle → It gets brand and year attributes from Vehicle.
  • Adds an additional attribute model → Represents the car's specific model (e.g., "Civic").
  • Uses super().__init__(brand, year) → Calls the parent class (Vehicle) constructor to initialize brand and year.

3️⃣ Displaying the Car Details

def display_info(self):
    print(f"Brand: {self.brand}\nYear: {self.year}\nModel: {self.model}")
  • Prints all the details (brand, year, model) in a formatted manner.
  • Overrides the parent class method (if Vehicle had one) to provide additional functionality.

4️⃣ Creating an Object and Calling the Method

car1 = Car("Honda", 2020, "Civic")
car1.display_info()
  • Creates an instance of Car with "Honda", 2020, and "Civic".
  • Calls display_info() to print the details.

Day 44

Question:

Create a Person class with attributes name and age. Define a method display_info() to print the person's details. Then, create a Student class that inherits from Person and adds an additional attribute student_id. Override the display_info() method in the Student class to display the student’s details, including the student_id.

Solution:

class Person:

    def __init__(self, name, age):

        self.name = name

        self.age = age

    def display_info(self):

        print(f"Name: {self.name}")

        print(f"Age: {self.age}")

class Student(Person):

    def __init__(self, name, age, student_id):

        Person.__init__(self, name, age)  

        self.student_id = student_id

    def display_info(self):

        print(f"Student Name: {self.name}")

        print(f"Age: {self.age}")

        print(f"Student ID: {self.student_id}")

person1 = Person("Radha", 30)

person1.display_info()

print() 

student1 = Student("Ram", 20, "S123")

student1.display_info()

Output:

Name: Radha

Age: 30

Student Name: Ram

Age: 20

Student ID: S123

Explanation:

1. Person Class (Parent Class)

  • Attributes:
    • name: Stores the name of the person.
    • age: Stores the age of the person.
  • Method:
    • display_info(): Prints the person's name and age.
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def display_info(self):
        print(f"Name: {self.name}")
        print(f"Age: {self.age}")

2. Student Class (Child Class)

  • Inherits from Person.
  • Additional Attribute:
    • student_id: Stores the student’s unique ID.
  • Overrides display_info() Method:
    • Prints Student Name, Age, and Student ID.
class Student(Person):
    def __init__(self, name, age, student_id):
        Person.__init__(self, name, age)  # Calling the parent class constructor
        self.student_id = student_id

    def display_info(self):
        print(f"Student Name: {self.name}")
        print(f"Age: {self.age}")
        print(f"Student ID: {self.student_id}")

3. Creating and Displaying Objects

person1 = Person("Radha", 30)
person1.display_info()
  • Creates a Person object with name "Radha" and age 30.
  • Calls display_info() from Person, which prints:
    Name: Radha
    Age: 30
    
student1 = Student("Ram", 20, "S123")
student1.display_info()
  • Creates a Student object with name "Ram", age 20, and student ID "S123".
  • Calls the overridden display_info() from Student, which prints:
    Student Name: Ram
    Age: 20
    Student ID: S123


 Day 45

Question:

Create a Product class with attributes name and price, and a method get_discount() that returns a default discount of 0%. Then, create two subclasses: Electronics, which overrides get_discount() to return a 10% discount, and Clothing, which overrides it to return a 20% discount. Finally, create a Laptop (Electronics) and a Shirt (Clothing), and display their respective discounts.

Solution:

class Product:

    def __init__(self, name, price):

        self.name = name

        self.price = price

    def get_discount(self):

        return 0  

    def get_final_price(self):

        discount_amount = (self.get_discount() / 100) * self.price

        return self.price - discount_amount

    def display_info(self):

        print(f"Product: {self.name}")

        print(f"Original Price: {self.price}")

        print(f"Discount: {self.get_discount()}%")

        print(f"Final Price: {self.get_final_price()}")

        print("-" * 30)

class Electronics(Product):

    def get_discount(self):

        return 10

class Clothing(Product):

    def get_discount(self):

        return 20  

laptop = Electronics("Laptop", 50000)

shirt = Clothing("Shirt", 2000)

laptop.display_info()

shirt.display_info()

Output:

Product: Laptop

Original Price: 50000

Discount: 10%

Final Price: 45000.0

------------------------------

Product: Shirt

Original Price: 2000

Discount: 20%

Final Price: 1600.0

------------------------------

Explanation:

1️⃣ Product Class (Base Class)

  • Attributes:
    • name: Stores the product name.
    • price: Stores the original price.
  • Methods:
    • get_discount(): Returns a default discount of 0% (no discount).
    • get_final_price():
      • Calculates the discount amount: discount_amount=(discount/100)×price\text{discount\_amount} = (\text{discount} / 100) \times \text{price}
      • Subtracts the discount from the original price and returns the final price.
    • display_info(): Prints product details (name, original price, discount, and final price).

2️⃣ Subclasses (Electronics & Clothing)

  • Both subclasses inherit from Product and override the get_discount() method to return specific discounts:
    • Electronics: 10% discount
    • Clothing: 20% discount

Since they inherit from Product, they automatically get all its attributes (name, price) and methods (get_final_price() and display_info()).

3️⃣ Creating Objects & Calling Methods

laptop = Electronics("Laptop", 50000)
shirt = Clothing("Shirt", 2000)
  • Creates two objects:
    • laptop belongs to Electronics with a price of ₹50,000.
    • shirt belongs to Clothing with a price of ₹2,000.
laptop.display_info()
shirt.display_info()
  • Calls display_info(), which:
    1. Displays the product name and price.
    2. Fetches the correct discount (get_discount() is overridden in each subclass).
    3. Computes and displays the final price after discount.

Day 46

Question:

Create a Payment class with subclasses CreditCard and UPI, each implementing a different pay() method.

Solution:

class Payment:

    def pay(self, amount):
        """Method to be implemented in subclasses"""
        pass

class CreditCard(Payment):

    def pay(self, amount):
        print(f"Paid {amount} using Credit Card")

class UPI(Payment):
    def pay(self, amount):
        print(f"Paid {amount} using UPI")

credit_card = CreditCard()

upi = UPI()

credit_card.pay(5000)

upi.pay(1200)

Output:

Paid 5000 using Credit Card
Paid 1200 using UPI

Explanation:

1️⃣ Parent Class: Payment

class Payment:
    def pay(self, amount):
        """Method to be implemented in subclasses"""
        pass
  • The Payment class acts as a base class (superclass).
  • It defines a pay() method but does not implement it.
  • The pass keyword is used to indicate that subclasses should override this method.

2️⃣ Subclass: CreditCard

class CreditCard(Payment):
    def pay(self, amount):
        print(f"Paid {amount} using Credit Card ")
  • Inherits from Payment.
  • Overrides the pay() method to process a credit card payment.
  • Prints a confirmation message including the amount paid.

3️⃣ Subclass: UPI

class UPI(Payment):
    def pay(self, amount):
        print(f"Paid {amount} using UPI ")
  • Inherits from Payment.
  • Overrides the pay() method to process a UPI payment.
  • Prints a confirmation message including the amount paid.

4️⃣ Creating Objects and Calling Methods

credit_card = CreditCard()
upi = UPI()

credit_card.pay(5000)  # Paying ₹5000 via Credit Card
upi.pay(1200)          # Paying ₹1200 via UPI
  • We create two objects, one for CreditCard and one for UPI.
  • We then call the pay() method on each object with a different amount.
  • Since CreditCard and UPI override the pay() method, Python calls the correct method depending on the object.

Day 47

Question:

Create a Employee class with name and base_salary.

  • Implement subclasses:
    • FullTimeEmployee: Adds a bonus to the salary.
    • PartTimeEmployee: Calculates salary based on hourly wage.
  • Override a method calculate_salary() in both subclasses.
  • Solution:

    class Employee:
        def __init__(self, name, base_salary):
            self.name = name
            self.base_salary = base_salary

        def calculate_salary(self):
            return self.base_salary

        def display_info(self):
            print(f"Name: {self.name},Salary: {self.calculate_salary()}")


    class FullTimeEmployee(Employee):
        def __init__(self, name, base_salary, bonus):
            super().__init__(name, base_salary)
            self.bonus = bonus

        def calculate_salary(self):
            return self.base_salary + self.bonus


    class PartTimeEmployee(Employee):
        def __init__(self, name, hourly_wage, hours_worked):
            super().__init__(name, base_salary=0) 
            self.hourly_wage = hourly_wage
            self.hours_worked = hours_worked

        def calculate_salary(self):
            return self.hourly_wage * self.hours_worked


    full_time = FullTimeEmployee("Arjun", 45000, 5000)
    part_time = PartTimeEmployee("Ravi", 500, 20)

    full_time.display_info()  
    part_time.display_info()  


    Output:

    Name: Arjun,Salary: 50000
    Name: Ravi,Salary: 10000

    Explanation:

    1️⃣ Employee Class (Parent Class)

    • Attributes:
      • name: Stores the employee’s name.
      • base_salary: Stores the employee’s fixed salary.
    • Methods:
      • calculate_salary(): Returns the base salary (this method is overridden in subclasses).
      • display_info(): Prints the employee’s name and calculated salary.

    2️⃣ FullTimeEmployee Class (Subclass)

    • Inherits from Employee.
    • Additional Attribute:
      • bonus: Extra salary added to the base salary.
    • Overrides calculate_salary():
      • Returns base_salary + bonus.

    Example:

    full_time = FullTimeEmployee("Arjun", 45000, 5000)
    
    • Base Salary: ₹45,000
    • Bonus: ₹5,000
    • Total Salary = ₹50,000

    3️⃣ PartTimeEmployee Class (Subclass)

    • Inherits from Employee.
    • New Attributes:
      • hourly_wage: Salary per hour.
      • hours_worked: Number of hours worked.
    • Overrides calculate_salary():
      • Returns hourly_wage × hours_worked.

    Example:

    part_time = PartTimeEmployee("Ravi", 500, 20)
    
    • Hourly Wage: ₹500
    • Hours Worked: 20
    • Total Salary = ₹10,000

    Day 48

    Question:

    Create an Order class with:

    • Attributes: order_id, items (list of items), and total_price.
    • Overload the + operator to merge two orders.
    • Implement a method calculate_discount() that returns different discounts for orders above ₹5000.

    Create two orders, merge them, and calculate the final price.

    Solution:

    class Order:
        def __init__(self, order_id, items, total_price):
            self.order_id = order_id
            self.items = items
            self.total_price = total_price

        def __add__(self, other):
            return Order(
                self.order_id + "-" + other.order_id, 
                self.items + other.items, 
                self.total_price + other.total_price
            )

        def calculate_discount(self):
            return self.total_price * 0.10 if self.total_price > 5000 else 0

        def final_price(self):
            return self.total_price - self.calculate_discount()

        def display_order(self):
            print(f"Order ID: {self.order_id}")
            print(f"Items: {', '.join(self.items)}")
            print(f"Total Price: {self.total_price}")
            print(f"Discount: {self.calculate_discount()}")
            print(f"Final Price: {self.final_price()}\n")


    order1 = Order("O101", ["Laptop", "Mouse"], 6000)
    order2 = Order("O102", ["Keyboard", "Headphones"], 4000)

    order1.display_order()
    order2.display_order()

    merged_order = order1 + order2
    merged_order.display_order()

    Output:

    Order ID: O101
    Items: Laptop, Mouse
    Total Price: 6000
    Discount: 600.0
    Final Price: 5400.0

    Order ID: O102
    Items: Keyboard, Headphones
    Total Price: 4000
    Discount: 0
    Final Price: 4000

    Order ID: O101-O102
    Items: Laptop, Mouse, Keyboard, Headphones
    Total Price: 10000
    Discount: 1000.0
    Final Price: 9000.0

    Explanation:

    1. __init__ Method (Constructor)

    def __init__(self, order_id, items, total_price):
        self.order_id = order_id
        self.items = items
        self.total_price = total_price
    
    • Initializes the order with:
      • order_id → Unique ID of the order
      • items → List of purchased items
      • total_price → Total cost of items

    2. Overloading the + Operator (__add__ Method)

    def __add__(self, other):
        return Order(
            self.order_id + "-" + other.order_id, 
            self.items + other.items, 
            self.total_price + other.total_price
        )
    
    • Allows merging two orders (order1 + order2)
    • Combines:
      • order_id → Merges both IDs with a -
      • items → Adds both lists of items together
      • total_price → Adds both order prices

    Example:

    order1 = Order("O101", ["Laptop", "Mouse"], 6000)
    order2 = Order("O102", ["Keyboard", "Headphones"], 4000)
    
    merged_order = order1 + order2
    print(merged_order.order_id)   # O101-O102
    print(merged_order.items)      # ['Laptop', 'Mouse','Keyboard','Headphones']
    print(merged_order.total_price)  # 10000
    

    3. Discount Calculation (calculate_discount Method)

    def calculate_discount(self):
        return self.total_price * 0.10 if self.total_price > 5000 else 0
    
    • If total_price > 5000, a 10% discount is applied
    • Otherwise, no discount is given

    Example:

    order1 = Order("O101", ["Laptop", "Mouse"], 6000)
    print(order1.calculate_discount())  # 600.0
    
    order2 = Order("O102", ["Keyboard", "Headphones"], 4000)
    print(order2.calculate_discount())  # 0
    

    4. Final Price Calculation (final_price Method)

    def final_price(self):
        return self.total_price - self.calculate_discount()
    
    • Final price = total_price - discount

    Example:

    order1 = Order("O101", ["Laptop", "Mouse"], 6000)
    print(order1.final_price())  # 5400
    

    5. Displaying Order Details (display_order Method)

    def display_order(self):
        print(f"Order ID: {self.order_id}")
        print(f"Items: {', '.join(self.items)}")
        print(f"Total Price: {self.total_price}")
        print(f"Discount: {self.calculate_discount()}")
        print(f"Final Price: {self.final_price()}\n")
    
    • Prints all order details, including discount and final price
    • Uses ', '.join(self.items) to display items as a comma-separated string

    Example Output:

    Order ID: O101
    Items: Laptop, Mouse
    Total Price: 6000
    Discount: 600.0
    Final Price: 5400.0
    

    6. Merging Two Orders and Displaying

    order1 = Order("O101", ["Laptop", "Mouse"], 6000)
    order2 = Order("O102", ["Keyboard", "Headphones"], 4000)
    
    order1.display_order()
    order2.display_order()
    
    merged_order = order1 + order2
    merged_order.display_order()
    
    • Merges order1 and order2 into merged_order
    • Displays the final order with combined items, total price,discount and final price

    Day 49

    Question:

    Create a Flight class with flight_number, origin, destination, and base_fare.

  • Implement subclasses EconomyFlight and BusinessFlight, each modifying fare calculation differently.
  • Implement a book_ticket() method to check seat availability and deduct a seat if available
  • Solution:

    class Flight:

        def __init__(self, flight_number, origin, destination, base_fare, seats):

            self.flight_number = flight_number

            self.origin = origin

            self.destination = destination

            self.base_fare = base_fare

            self.seats = seats

        def calculate_fare(self):

            return self.base_fare

       def book_ticket(self):

            if self.seats > 0:

                self.seats -= 1

                print(f"Ticket booked for {self.flight_number}. Seats left: {self.seats}")

            else:

                print(f"Sorry, {self.flight_number} is full.")

    class EconomyFlight(Flight):

        def calculate_fare(self):

            return self.base_fare * 0.9  

    class BusinessFlight(Flight):

        def calculate_fare(self):

            return self.base_fare * 1.5 

    economy = EconomyFlight("E101", "Delhi", "Mumbai", 5000, 3)

    business = BusinessFlight("B202", "Delhi", "London", 20000, 2)

    economy.book_ticket()

    business.book_ticket()

    business.book_ticket()

    business.book_ticket()  

    Output:

    Ticket booked for E101. Seats left: 2
    Ticket booked for B202. Seats left: 1
    Ticket booked for B202. Seats left: 0
    Sorry, B202 is full.

    Explanation:

    1. Base Class: Flight

    The Flight class contains common properties and methods for all flights.

    Attributes in Flight Class:

    • flight_number: The flight’s unique identifier (e.g., "E101").
    • origin: Departure location (e.g., "Delhi").
    • destination: Arrival location (e.g., "Mumbai").
    • base_fare: The base ticket price.
    • seats: Number of available seats.

    Methods in Flight Class:

    • calculate_fare(): Returns the base fare (can be overridden in subclasses).
    • book_ticket(): Checks if a seat is available and books it if possible.

    2. Subclasses: EconomyFlight and BusinessFlight

    We create two subclasses that modify the fare calculation.

    EconomyFlight Class:

    • Inherits from Flight
    • Overrides calculate_fare() to apply a 10% discount (fare = base_fare * 0.9).

    BusinessFlight Class:

    • Inherits from Flight
    • Overrides calculate_fare() to apply a 50% extra charge (fare = base_fare * 1.5).

    3. Creating and Booking Flights

    • We create an Economy Flight (E101) from Delhi to Mumbai, with a base fare of ₹5000 and 3 seats available.
    • We create a Business Flight (B202) from Delhi to London, with a base fare of ₹20,000 and 2 seats available.
    • We book tickets for both flights.
    • If no seats are left, it displays "Sorry, B202 is full."

    Day 50

    Question:

    Book class with title, author, available_status.

    • Library class that has a list of books and allows users to borrow or return books.
    • Ensure books can't be borrowed if unavailable.

    Solution:

    class Book:
        def __init__(self, title, author):
            self.title = title
            self.author = author
            self.available_status = True 

        def borrow(self):
            if self.available_status:
                self.available_status = False
                print(f"You have borrowed '{self.title}'.")
            else:
                print(f"Sorry, '{self.title}' is not available.")

        def return_book(self):
            self.available_status = True
            print(f"You have returned '{self.title}'.")

    class Library:
        def __init__(self):
            self.books = []

        def add_book(self, book):
            self.books.append(book)

        def display_books(self):
            print("\nAvailable Books:")
            for book in self.books:
                status = "Available" if book.available_status else "Not Available"
                print(f"{book.title} by {book.author} - {status}")

    library = Library()

    book1 = Book("Python Programming", "John Doe")
    book2 = Book("Data Science Basics", "Jane Smith")

    library.add_book(book1)
    library.add_book(book2)

    library.display_books()

    book1.borrow()
    library.display_books()

    book1.borrow()

    book1.return_book()
    library.display_books()

    Output:

    Available Books:
    Python Programming by John Doe - Available
    Data Science Basics by Jane Smith - Available
    You have borrowed 'Python Programming'.

    Available Books:
    Python Programming by John Doe - Not Available
    Data Science Basics by Jane Smith - Available
    Sorry, 'Python Programming' is not available.
    You have returned 'Python Programming'.

    Available Books:
    Python Programming by John Doe - Available
    Data Science Basics by Jane Smith - Available

    Explanation:

    1. Book Class (Represents Individual Books)

    Each book has:

    • title: The book's name.
    • author: The author's name.
    • available_status: A boolean (True or False) to check if the book is available.

    Methods in Book Class

    1. borrow()

      • If the book is available (available_status = True), it marks it as borrowed (available_status = False) and displays a message.
      • If already borrowed (available_status = False), it shows a "not available" message.
    2. return_book()

      • Marks the book as available again (available_status = True).
      • Displays a message confirming the return.

    2. Library Class (Manages Multiple Books)

    The Library class stores multiple books and provides methods to manage them.

    Methods in Library Class

    1. __init__()

      • Initializes an empty list (self.books) to store books.
    2. add_book(book)

      • Adds a Book object to the books list.
    3. display_books()

      • Loops through all books in self.books.
      • Prints their title, author, and availability status.

    3. How the Program Works

    1. Create a Library

      library = Library()
      
      • Creates an empty Library object.
    2. Create and Add Books

      book1 = Book("Python Programming", "John Doe")
      book2 = Book("Data Science Basics", "Jane Smith")
      
      library.add_book(book1)
      library.add_book(book2)
      
      • Two books are created and added to the library.
    3. Display Available Books

      library.display_books()
      
      • Shows a list of books along with their availability status.
    4. Borrow a Book

      book1.borrow()
      
      • If available, the book is borrowed, and its status changes to "Not Available".
      • If unavailable, it displays an error message.
    5. Try Borrowing an Already Borrowed Book

      book1.borrow()
      
      • Since the book is already borrowed, an error message is displayed.
    6. Return the Book

      book1.return_book()
      
      • Marks the book as available again.
    7. Final Book List Display

      library.display_books()
      
      • Shows updated book availability.


    Comments