Loop Control Statements in C Introduction to HTML How to use the Github API The image tag, anchor tag and the button tag Ordered and Unordered Lists in HTML The division tag HTML Forms Tables in HTML Introduction to C Programming Introduction to Python Varibles and Datatypes in Python Operators in Python Typecasting in Python Input and Output in Python If Else in Python Loops in Python Break, Continue and Pass in Python Python practice section 1 Lists in Python Tuple in Python

Object Oriented Programming in Python

Object Oriented Programming is a programming paradigm that makes use of Classes and objects. It makes the code readable and easy to understand. It helps to hide unnecessary details from the user and helps in the reusability of code.
There are 6 pillars of OOPs - Class, Object, Inheritance, Encapsulation, Polymorphism and Data Abstraction.

Class

A class is the basic building block. It defines the properties and the methods of an object. It does not represent a real-world entity instead it is used to define the characteristics and the behavior of the objects. For example - the word 'fruit' is used to describe a set of items having characteristics like water percentage, shape, color, sourness, sweetness, etc. Hence, sour, sweet, watery, etc. are the attributes that define a fruit. There is no real thing named 'fruit'.

class Fruit:

    def __init__(self,water_percentage,shape,color,sourness,sweetness):

        self.water_percentage=water_percentage
        self.shape=shape
        self.color=color
        self.sourness=sourness
        self.sweetness=sweetness

Object

An object is a real-world entity with pre-defined behavior and properties. For example - Mango is a fruit having properties like round, yellow, sweet, etc. A mango is a real thing and is the object of the fruit class.

mango=Fruit(40, "round", "yellow",20,80)
grapes=Fruit(70, "round", "green",50,50)

Inheritance

Different classes can share a common behavior such as both Person Class and Employee Class having a name, age, phone number, etc. The Employee Class can have additional properties like salary, company_working_at etc. Hence, instead of implementing the same details in the Employee Class, we can inherit these properties from the Person class and use them without having to write the same information again at a new place.

class Person:

    def __init__(self,name,age,phone_number) -> None:

        self.name=name
        self.age=age
        self.phone_number=phone_number

class Employee(Person):  # Inherits the person class

def __init__(self,name,age,phone_number,emp_id,company_working_at,salary) -> None:

        # To use the properties and methods of SuperClass, we call the init method of SuperClass.
        super().__init__(name,age,phone_number)     
          
        self.emp_id=emp_id
        self.company_working_at=company_working_at
        self.salary=salary

e=Employee("sumit",31,45678,2112,"TCS",45000)
print(f"Name = {e.name}, Age = {e.age}, Phone Number = {e.phone_number}, Employee Id = {e.emp_id},\\\
       Company Working at = {e.company_working_at}, Salary = {e.salary}")
Output
Name =  sumit, Age =  31, Phone Number =  45678, Employee Id =  2112, Company Working at =  TCS, Salary =  45000

Encapsulation

Encapsulation means combining the methods and properties inside a single class. It prevents objects of the other class from changing and accessing the properties and methods of a class. It helps to achieve data hiding. For example - we can have private variables and methods in a class that cannot be accessed or modified by the objects of another class.

class Person:

    def __init__(self,name,age,phone_number) -> None:

        self.name=name
        self.age=age

        # Private variable
        self.__phone_number=phone_number

    # Private method
    def __changePhoneNumber(self,newPhoneNumber):

        self.phone_number=newPhoneNumber

class Student(Person):

    def __init__(self,name,age,rollno,grade) -> None:

        self.rollno=rollno
        self.grade=grade

        # Invoking the constructor method of the base class.
        super().__init__(name,age,phone_number)

s1=Student("ravi",15,1012,'B')
print(s1.rollno)
print(s1.phone_number)     # Generates an AttributeError
Output
1012
Traceback (most recent call last):
  File "c:\Users\HP\OneDrive\Desktop\aditi jain\Rapid Coders Articles\python.py", line 16, in 
    print(s1.phone_number)
AttributeError: 'Student' object has no attribute 'phone_number'
        

Polymorphism

Polymorphism means many. It is used to represent the idea of one having many forms. For example - Multiple classes can inherit a single BaseClass and override one of its methods to provide their own implementation of the method.

class Animal:

    def speak(self):
        print("Animal Sound")

class Dog(Animal):

    def speak(self):
        print("Bho Bho Bho !")
    
class Cat(Animal):

        def speak(self):
            print("Meow Meow !")

daisy=Cat()
daisy.speak()

harry=Dog()
harry.speak()
Output
Bho Bho Bho !
Meow Meow !

Data Abstraction

Data Abstraction means hiding unnecessary details from the user. The user does not know the internal working. The user only knows about the properties and the behavior of a class without knowing how they are implemented. It helps to hide crucial information from the user.

class Item:

    def __init__(self,mrp_price):

        self.mrp_price=mrp_price

    def calculate_price(self,gst_rate,discount_rate):

        net_amount=self.mrp_price+(self.mrp_price*gst_rate)
        price_to_pay=net_amount-(net_amount*discount_rate)
        return price_to_pay

price=int(input("Enter mrp of item : "))

item=Item(price)

print("Initial price = ",price)

gst_rate=8
discount_rate=20

print("Price to pay = ",item.calculate_price(gst_rate,discount_rate))
Output
Enter mrp of item : 2000
Initial price =  2000
Price to pay =  1728.0 
Here, the end user does not know how the price to pay is calculated from the mrp_price. The user only inputs the mrp of an item and gets the price_to_pay from the system thereby hiding the details of how price_to_pay is calculated.