Python Object Oriented Programming



Object Oriented Programming

Python is a multi-paradigm programming language. It supports various programming approaches.

One of the popular approaches supported by Python is Object-Oriented Programming (OOP). OOP is a fundamental programming paradigm used by nearly every developer and taught as the standard way to code for most programmers.

OOP is used to solve programming problems by creating objects.

An object has two characteristics:

  • attributes (variables)
  • behavior (methods)

Let us see the following example:

A dog is an object, as it has the following properties:

  • name, age, color, height, weight as attributes
  • sit, lay down, shake, come as behaviors

The main concept of OOPs is to create objects, re-use them throughout the program, and manipulate these objects to get results. The concept of reusable code is also known as DRY (Don't Repeat Yourself).

In Python, the concept of OOP follows some basic principles:


Class

A Class is a blueprint for the structure of methods and attributes. Individual objects are instantiated or created from a class.

A class contains fields for attributes and methods for behaviors. For example, in the Dog class, attributes include name, age, color, while methods include sit(), layDown(), shake().

The example for a class of Dog can be given as follows:

class Dog:
    pass

As we can see above, we used the class keyword to define an empty class Dog.

From a class, we can construct instances. An instance is a specific object created from a class.


Object

An object is an instance of a class created with specific data. An object can correspond to real-world objects or an abstract entity. When a class is defined, only the description for the object is defined. Therefore, no memory or storage is allocated.

In the following example, we will create an object of the Dog class:

dogObj = Dog()

Here, dogObj is an object of class Dog.

Let us suppose we have details of the Dog class. Now, we are going to show how to build the class and objects of dogs.


Example: Creating Class and Object in Python

class Dog:

    # class attribute
    number_of_instances = 0

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Dog.number_of_instances += 1

# instantiate the Dog class
luna = Dog("Luna", 2)
max = Dog("Max", 3)

# access the class attributes
print("The number of dog instances: {}".format(Dog.number_of_instances))
print("The number of dog instances through 'max' instance: {} ".format(max.__class__.number_of_instances))

# access the instance attribute
print("{} is {} years old".format(luna.name, luna.age))
print("{} is {} years old".format(max.name, max.age))

Output

The number of dog instances: 2
The number of dog instances through 'max' instance: 2 
Luna is 2 years old
Max is 3 years old

In the above program, we created a class with the name Dog. Then, we define attributes (class and instance attributes). The attributes are a characteristic of an object.

These attributes are defined inside the __init__ method of the class. The __init__ method is the initializer method that runs first as soon as the object is created.

Then, we create instances of the Dog class. We create luna and max that are references to our new objects.

We can access the class attribute using the Dog class or __class__.species of the instance. Class attributes are the same for all instances of a class.

Similarly, we can access the instance attributes using luna.name and luna.age. But, instance attributes are different for every instance of a class.


Instance Methods

Instance methods are functions that are defined inside a class and can only be called from an instance of that class. The instance method's first parameter is always self.


Example: Creating instance methods in Python

class Dog:

    # class attribute
    number_of_instances = 0

    def __init__(self, name, age):
        self.name = name
        self.age = age
        Dog.number_of_instances += 1

    # instance method
    def sit(self):
        return "{} is now sitting".format(self.name)

    def shake(self):
        return "{} is now shaking".format(self.name)

# instantiate an object
luna = Dog("Luna", 2)

# call instance methods of Dog class
print(luna.sit())
print(luna.shake())

Output

Luna is now sitting
Luna is now shaking

In the above program, we define two instance methods i.e sit() and shake(). These methods are called instance methods because they are called on an instance object i.e luna.


Inheritance

Inheritance is a way of creating a new class by using details of an existing class without modifying it. The newly formed class is a derived (or child class). Similarly, the existing class is a base class (or parent class).


Example: Use of Inheritance in Python

# parent class
class Animal:

    def __init__(self):
        print("Animal is ready")

    def whoisThis(self):
        print("Animal")

    def walk(self):
        print("walk faster")

# child class
class Dog(Animal):
    
    def __init__(self):
        # call super() function
        super().__init__()
        print("Dog is ready")

    def whoisThis(self):
        print("Dog")

    def run(self):
        print("Run faster")

dog1 = Dog()
dog1.whoisThis()
dog1.walk()
dog1.run()

Output

Animal is ready
Dog is ready
Dog
walk faster
Run faster

In the above program, we created two classes i.e. Animal (parent class) and Dog (child class). The child class inherits functions of the parent class (Animal). We can see this from the walk() method.

The child class can also modify the behavior of the parent class. We can see this through the whoisThis() method.

The child class can extend the parent class functions by creating new functions like the run() method.

As we can see, we used the super() function inside the __init__() method. This allows us to run the __init__() method of the parent class inside the child class.


Encapsulation

The encapsulation principle states that all-important information is enclosed inside an object, and only select information is exhibited. The implementation and state of each object are privately kept inside a defined class. Other objects do not have access to this class or the right to make changes; they can only call a list of public functions or methods.

In Python, we use encapsulation to restrict access to methods and variables. In Python, to prevent data from direct modifications, we denote private attributes using underscore as the prefix single _ or double __.


Example: Data Encapsulation in Python

class Bicycle:

    def __init__(self):
        self.__price = 300

    def sell(self):
        print("Selling price: {}".format(self.__price))

    def setPrice(self, price):
        self.__price = price

b = Bicycle()
b.sell()

# change the price
b.__price = 400
b.sell()

# using setter function to change price 
b.setPrice(400)
b.sell()

Output

Selling price: 300 
Selling price: 300 
Selling price: 400

In the above program, we defined a Bicycle class.

We used the __init__() method to save the selling price of Bicycle. We tried the modify the price directly using b.__price = 400. But, it is not possible because Python treats the __price as private attributes.

To change the price of Bicycle, we need to use a setter function setPrice() that takes price as a parameter.


Polymorphism

Objects are designed to share behaviors, and they can take on more than one form. The program will determine which usage is necessary for each execution of that object, reducing the need to duplicate code.

In other words, polymorphism is the ability to use a common interface for multiple forms.


Example: Using Polymorphism in Python

class Dog():
    
    def bark(self):
        print("Dog can bark")

    def meow(self):
        print("Dog can't meow")

class Cat():
    
    def bark(self):
        print("Cat can't bark")

    def meow(self):
        print("Cat can meow")

# common interface
def bark_test(animal):
    animal.bark()

# instantiate objects
d = Dog()
c = Cat()

# passing the object
bark_test(d)
bark_test(c)

Output

Dog can bark 
Cat can't bark

In the above program, we defined two classes, Dog and Cat. Each of them has a common bark() method. But, their functions are different.

To implement polymorphism, we created a common interface bark_test() function that takes any object and calls the object's bark() method. So, when we passed the d and c objects in the bark_test() function, it ran effectively.


Important Points to Remember:

  • Object-Oriented Programming (OOP) makes the program elegant, easy to understand, and efficient.
  • OOP encourages code reuse.
  • Data is safe and secure with data encapsulation.
  • Polymorphism allows the same interface for different objects, so developers can write efficient code.


ExpectoCode is optimized for learning. Tutorials and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. While using this site, you agree to have read and accepted our terms of use, cookie and privacy policy.
Copyright 2020-2021 by ExpectoCode. All Rights Reserved.