Object-Oriented Programming in Python

Learn about object-oriented programming concepts in Python.

45 min read
Intermediate

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.

python
class Student:
      pass

Class 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.

python
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.

python
class Student:
  def study(self):
      print("The student is studying.")

john = Student()

Now, let us check the data type of the variable john.

python
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.

python
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.

python
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.

python
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

The variables values can then be accessed easily as,

python
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.

python
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.

python
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.

python
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.

python
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.

python
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.

python
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,

python
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.

python
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.

python
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.

python
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.

python
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.

python
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.

Test your knowledge

🧠 Knowledge Check
1 / 15

What is an object in Python OOP?