Object Oriented Programming

What is Object Oriented Programming?
Major principles of object-oriented programming system are:

Advantages of object oriented programming:

  1. Improved software-development productivity:

    • Provides improved software-development productivity over traditional procedure-based programming techniques due to below factors.
      1. Modularity: Provides separation of duties in object-based program development.
      2. Extensibility: Objects can be extended to include new attributes and behaviors.
      3. Reusability: Objects can also be reused within an across applications.
  2. Improved software maintainability:

    • For the reasons mentioned above, it is easier to maintain.

    • Since the design is modular, part of the system can be updated in case of issues without a need to make large-scale changes.

  3. Faster development:

    • Reuse enables faster development.

    • Come with rich libraries of objects, and code developed during projects is also reusable in future projects.

  4. Lower cost of development:

    • Typically, more effort is put into the object-oriented analysis and design, which lowers the overall cost of development.
  5. Higher-quality software:

    • Faster development of software and lower cost of development allows more time and resources to be used in the verification of the software.

    • Although quality is dependent upon the experience of the teams, it tends to result in higher-quality software.

Disadvantages of object oriented programming:

Example of Python Class:
class Dog:
    species = 'mammal'
    legs = 4
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def description(self):
        print("{} is {} years old".format(self.name, self.age))
        
    def bark(self):
        print("Bhaun.. Bhaun..")

        
dog_a = Dog("Roger", 8)
dog_b = Dog("Lysa", 5)
dog_a.description() 
dog_a.bark()

## Output: ##
# Roger is 8 years old.
# Bhaun.. Bhaun..

Classes

Objects(Instances)

Methods

Inheritance

# parent class
class Bird:
    def __init__(self):
        print("Bird is ready")
        
    def whoisThis(self):
        print("Bird")
        
    def swim(self):
        print("Swim faster")

        
# child class
class Penguin(Bird):
    def __init__(self):
        # call super() function
        super().__init__()
        print("Penguin is ready")
        
    def whoisThis(self):
        print("Penguin")
        
    def run(self):
        print("Run faster")

peggy = Penguin()
peggy.whoisThis()
peggy.swim()
peggy.run()


## Output ##
# Bird is ready
# Penguin is ready
# Penguin
# Swim faster
# Run faster
Note:

We used super( ) function before __init__( ) method.

This is because we want to pull the content of __init__( ) method from the parent class into the child class.

Multi-Inheritance

Multi-ple Inheritance
class Base1:
    pass
 
class Base2:
    pass
  
class MultiDerived(Base1, Base2):
    pass

MultipleInheritance

Multi-level Inheritance
class Base:
    pass
  
class Derived1(Base):
    pass
  
class Derived2(Derived1):
    pass

MultilevelInheritance

Method Resolution Mechanism:

Output:
>>> MultiDerived.__mro__
(<class '__main__.MultiDerived'>,
 <class '__main__.Base1'>,
 <class '__main__.Base2'>,
 <class 'object'>)

>>> MultiDerived.mro()
[<class '__main__.MultiDerived'>,
 <class '__main__.Base1'>,
 <class '__main__.Base2'>,
 <class 'object'>]
Complex Example
class X: pass
class Y: pass
class Z: pass

class A(X,Y): pass
class B(Y,Z): pass
class M(B,A,Z): pass

print(M.mro())

Output:

[<class '__main__.M'>, <class '__main__.B'>,
 <class '__main__.A'>, <class '__main__.X'>,
 <class '__main__.Y'>, <class '__main__.Z'>,
 <class 'object’>]

Polymorphism

Polymorphism is considered as one of the important features of Object Oriented Programming.

Polymorphism is mainly divided into two types:

  1. Compile time Polymorphism
  2. Runtime Polymorphism

Compile time Polymorphism

This type of polymorphism is achieved by:

Function/Method Overloading

# First product method: takes 2 argument and print their product
def product(a, b):
    p = a * b
    print(p)
    
# Second product method: takes 3 argument and print their product
def product(a, b, c):
    p = a * b*c
    print(p)

    
# Below line shows an error
product(4, 5)
# => Gives error

# This line will call the second product method
product(4, 5, 5)
#=> 100
class Human:
    def sayHello(self, name=None):
        if name is not None:
            print 'Hello ' + name
        else:
            print 'Hello '

# Create instance
obj = Human()

# Call the method
obj.sayHello()
# => Hello

# Call the method with a parameter
obj.sayHello('Astik')
# => Hello Astik

Operator Overloading

import math
class Circle:
    def __init__(self, radius):
        self.__radius = radius
        
    def setRadius(self, radius):
        self.__radius = radius
        
    def getRadius(self):
        return self.__radius
      
    def area(self):
        return math.pi * self.__radius ** 2
      
    def __add__(self, another_circle):
        return Circle( self.__radius + another_circle.__radius )
      
    def __gt__(self, another_circle):
        return self.__radius > another_circle.__radius
      
    def __lt__(self, another_circle):
        return self.__radius < another_circle.__radius
      
    def __str__(self):
        return "Circle with radius " + str(self.__radius)

      
c1 = Circle(4)
print(c1.getRadius())
c2 = Circle(5)
print(c2.getRadius())
c3 = c1 + c2
print(c3.getRadius())
print( c3 > c2) # Became possible because we have added __gt__ method
print( c1 < c2) # Became possible because we have added __lt__ method
print(c3) # Became possible because we have added __str__ method

Output:

4
5
9
True
True
Circle with radius 9

operator_overloading

Run Time Polymorphism

This type of polymorphism is achieved by:

Method Overriding

class Rectangle():
    def __init__(self, length, breadth):
        self.length = length
        self.breadth = breadth
        
    def getArea(self):
        print self.length*self.breadth," is area of rectangle"

        
class Square(Rectangle):
    def __init__(self, side):
        self.side = side
        Rectangle.__init__(self,side,side)
    def getArea(self):
        print self.side*self.side," is area of square"

        
s = Square(4)
r = Rectangle(2,4)
s.getArea()
r.getArea()

Output:

16
16

Encapsulation (Data Abstraction)

class Computer:
    def __init__(self):
        self.__maxprice = 900
        
    def sell(self):
        print("Selling Price: {}".format(self.__maxprice))
        
    def setMaxPrice(self, price):
        self.__maxprice = price

        
c = Computer()
c.sell()

# change the price
c.__maxprice = 1000
c.sell()

# using setter function
c.setMaxPrice(1000)
c.sell()

Output:

Selling Price: 900
Selling Price: 900
Selling Price: 1000