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.