Object-Oriented Programming in Python
Learn about object-oriented programming concepts in Python.
Introduction
Object Oriented Programming (OOP) involves the use of objects for modelling complex systems. Unlike procedure oriented programming, where the main emphasis is on functions, object oriented programming stresses on objects.
An object is a collection of data (variables) and methods (functions) that act on those data. Similarly, a class is a blueprint for that object.
For example, a car manafacturing company may have a class called 'car' which describes that overall design of a car. Using this class blueprint, the company can engineer and produce real-world cars, which are the objects.
Object Oriented Analysis (OOA) is the process of examining a problem, system or task and identifying the objects and interactions between them.
Why use classes?
- Classes allow us to logically group our data and functions in a way that it is easier to reuse and further build upon.
- It is generally easier to read, understand, and maintain.
- Classes provide us with a powerful tool for abstraction. Abstraction is when we forget about details of how something works and just concentrate on using it.
Defining a class
The syntax for defining a class in Python is as follows where the first letter of 'Classname' is capitalized by convention:
class Classname:
# class body
For example, let's define a Student class. Just like functions, running this code does not produce any output. It simply creates the class blueprint.
class Student:
passClass methods
A class can contain methods (functions) related to it.
The syntax for defining a method in a class is as follows:
class ClassName:
def method_name(self):
# method body
Note: The method of a class always takes self as the default parameter. self points the method to the current object instance.
For this example, we will define a method study for our class Student. Unless we call this method, it will not produce any output.
class Student:
def study(self):
print("The student is studying.")Instantiating an Object
The instance of a class is known as an Object. Classes can be used to instantiate an object of data type class by simply calling it.
The syntax for creating an object from a class is as follows,
object_name = ClassName()
Let us create an object john from our class Student.
class Student:
def study(self):
print("The student is studying.")
john = Student()Now, let us check the data type of the variable john.
print(type(john))And, we can see that it is of the type 'Student' which is our class.
Now that we have our class object, we can use it to access and call any methods in our class using the following syntax:
object_name.method_name()
Let's see an example by calling the study method using our object john.
class Student:
def study(self):
print("The student is studying.")
john = Student()
john.study()Congratulations! We've created our first class, wrote its method study, instantiated an object john, and called the method using that object john.study().
We can also create multiple objects using the same class. Let us define two objects as student1 and student2.
class Student:
def study(self):
print("The student is studying.")
# Creating two objects
student1 = Student()
student2 = Student()In practice, different objects will have different values and therefore, we can set different values for each object using the syntax:
object_name.variable_name = value
Let us set the variable values such as first name, last name and roll number for each student.
class Student:
def study(self):
print("The student is studying.")
# Creating two objects
student1 = Student()
student2 = Student()
# Setting values for student1
student1.fname = "John"
student1.lname = "Rogers"
student1.roll = 28
# Setting values for student2
student2.fname = "Rosy"
student2.lname = "Smith"
student2.roll = 12The variables values can then be accessed easily as,
class Student:
def study(self):
print("The student is studying.")
# Creating two objects
student1 = Student()
student2 = Student()
# Setting values for student1
student1.fname = "John"
student1.lname = "Rogers"
student1.roll = 28
# Setting values for student2
student2.fname = "Rosy"
student2.lname = "Smith"
student2.roll = 12
print(student1.roll)
print(student2.fname)
student2.study()In most cases, we want to be able to set these values when instantiating an object itself rather than setting the values after instantiating the object.
Let's see how we can do that using a 'constructor' method in a class.
Constructor in Python
A constructor is a special class method that is defined by the name __init__() and can be used to initialize one or more variables or properties. It is automatically called when we create a new object from a class.
The syntax for defining variable values using constructor is as follows:
class ClassName:
def __init__(self, variable_name):
self.variable_name = variable_name
def method_name(self):
# function body
Note here that the method of the class contains self as the parameter, which points to the current object instance of the class. This instance can hence be used by the method to access the variables that were declared in our constructor method using the syntax:
self.variable_name
Now, let's define a constructor for our Student class to initialize the variables first_name, last_name, class_num, and subject.
class Student:
def __init__(self, first_name, last_name, class_num, subject):
self.fname = first_name
self.lname = last_name
self.class_no = class_num
self.sub = subject
def study(self):
print("The student is studying", self.sub)
def get_details(self):
print("First Name:", self.fname)
print("Last Name:", self.lname)
print("Class:", self.class_no)Let us instantiate an object from our class. The class needs parameters first_name, last_name, class and subject as specified in the constructor.
class Student:
def __init__(self, first_name, last_name, class_num, subject):
self.fname = first_name
self.lname = last_name
self.class_no = class_num
self.sub = subject
def study(self):
print("The student is studying", self.sub)
def get_details(self):
print("First Name:", self.fname)
print("Last Name:", self.lname)
print("Class:", self.class_no)
student1 = Student("John", "Rogers", 5, "Mathematics")
student2 = Student("Mary", "May", 6, "English")
# Accessing the variables
print(f'Full Name: {student1.fname} {student1.lname}')
print(f'Class: {student1.class_no}')
# Printing a new line for better readability
print('\n')
print(f'Full Name: {student2.fname} {student2.lname}')
print(f'Class: {student2.class_no}')We can also call the methods defined in our class using the object instances.
class Student:
def __init__(self, first_name, last_name, class_num, subject):
self.fname = first_name
self.lname = last_name
self.class_no = class_num
self.sub = subject
def study(self):
print("The student is studying", self.sub)
def get_details(self):
print("First Name:", self.fname)
print("Last Name:", self.lname)
print("Class:", self.class_no)
student1 = Student("John", "Rogers", 5, "Mathematics")
student2 = Student("Mary", "May", 6, "English")
# Calling the methods
student1.get_details()
student1.study()
# Printing a new line for better readability
print('\n')
student2.get_details()
student2.study()You can now fully understand the importance of the __init__() constructor method in initializing variable values while creating an object from a class.
Changing variable values inside of a class
After initializing the values in the constructor method, these values can also be changed through methods or assignments.
Suppose we need to change the class number of each student every year with an increment of 1. We will be adding a new method increment_class to our class Student.
class Student:
def __init__(self, first_name, last_name, class_num, subject):
self.fname = first_name
self.lname = last_name
self.class_no = class_num
self.sub = subject
def study(self):
print("The student is studying", self.sub)
self.get_details()
def get_details(self):
print("First Name:", self.fname)
print("Last Name:", self.lname)
print("Class:", self.class_no)
def increment_class(self):
self.class_no = self.class_no + 1
# Instantiating an object
student1 = Student("John", "Rogers", 5, "Mathematics")
# Calling the method to see initial details
student1.get_details()
# Incrementing the class number
student1.increment_class()
# Calling the method again to see updated details
student1.get_details()Upon checking the value of our variable class_no, we can see that the grade of the student has been incremented by 1.
print(student1.class_no)Inheritance in Python
Inheritance is a very important feature of classes and objects in Python. It is based on similar ideas used in other object-oriented languages such as Java, C++ etc.
Using inheritance, a new class can be derived from an existing class as follows:
class BaseClass():
pass
class DerivedClass(BaseClass):
pass
To illustrate this, let us first create a parent class School with a method exam.
class School:
def exam(self):
print("Exams have been scheduled.")Now, let's again create our class Student but this time we can inherit from School as follows,
class School:
def exam(self):
print("Exams have been scheduled.")
class Student(School):
def __init__(self, subject):
self.sub = subject
def study(self):
print("The student is studying:", self.sub)We can now instantiate the object for Student class as we did before, i.e., by calling the class Student with a parameter subject.
class School:
def exam(self):
print("Exams have been scheduled.")
class Student(School):
def __init__(self, subject):
self.sub = subject
def study(self):
print("The student is studying:", self.sub)
# Instantiate an object
student1 = Student("Mathematics")
# Object is of class type Student
print(type(student1))Now, as the Student class is inherits from the School class, the student object can be used to access methods (functions) from both the Student and School class.
class School:
def exam(self):
print("Exams have been scheduled.")
class Student(School):
def __init__(self, subject):
self.sub = subject
def study(self):
print("The student is studying:", self.sub)
# Instantiate an object
student1 = Student("Mathematics")
# Accessing the methods from its own class (Student)
student1.study()
# Accessing the method from the parent class (School)
student1.exam()We can also view all the different details about the class Student by using the help function.
help(Student)It shows that the class is inherited from School and the methods that have been inherited along with it.
We've seen how to inherit methods from a parent class. Let's see how we can access variables from a parent class.
class School:
def __init__(self, roll):
self.roll_no = roll
def exam(self):
print("Exams have been scheduled.")
class Student(School):
def __init__(self, subject, roll_no):
# Calling the constructor of the parent class and passing roll_no
School.__init__(self, roll_no)
self.sub = subject
def study(self):
print("The student is studying:", self.sub)
student = Student("Mathematics", 28)
# Calling the method from the parent class
student.exam()
# Accessing the variable inherited from the parent class
print("Roll Number:", student.roll_no)A more convenient way to inherit variables from the parent class is to use the super() function. The super() function returns a temporary object of the super class (parent class) that allows us to call its methods.
class School:
def __init__(self, roll):
self.roll_no = roll
def exam(self):
print("Exams have been scheduled.")
class Student(School):
def __init__(self, subject, roll_no):
# Using super() to inherit from parent class
super().__init__(roll_no)
self.sub = subject
def study(self):
print("The student is studying:", self.sub)
student = Student("Mathematics", 28)
# Calling the method from the parent class
student.exam()
# Accessing the variable inherited from the parent class
print("Roll Number:", student.roll_no)With that we conclude our lesson on the fundamentals of Object Oriented Programming in Python.