Skip to main content

Object-Oriented Programming

Object-oriented programming (OOP) is a programming paradigm that organizes code around objects. Python provides powerful OOP features that make it easier to build reusable, maintainable, and extensible applications.

Topics Covered

In this module, you’ll learn:
  1. OOP Refresher
  2. Class Members vs Instance Members
  3. Class Methods
  4. Static Methods
  5. Magic (Dunder) Methods
  6. Abstract Base Classes (ABC)
  7. Multiple Inheritance
  8. Method Resolution Order (MRO)
  9. Best Practices
Try Yourself: 💻 VS Code | 🚀 Colab | 📥 Download
Verify Solutions: 💻 VS Code | 🚀 Colab | 📥 Download
By the end of this module, you’ll understand how Python objects work internally, customize object behavior, design reusable class hierarchies, and apply advanced OOP concepts effectively.

OOP Refresher

Before exploring advanced concepts, let’s quickly revisit the fundamentals of object-oriented programming.

What is OOP?

Object-Oriented Programming (OOP) is a programming paradigm that organizes code around objects. An object combines:
  • Attributes (data)
  • Methods (behavior)

Class and Object

A class is a blueprint for creating objects. An object is an instance of a class.
Output ?

The Four Pillars of OOP

Python supports four fundamental principles of OOP. In this module, we’ll build upon these fundamentals and explore advanced OOP concepts.

Everything in Python is an Object

Python follows an object-oriented design where everything is an object—numbers, strings, lists, dictionaries, functions, modules, and even classes. Every object has:
  • Identity (id())
  • Type (type())
  • State (data)
  • Behavior (methods)

Classes are Objects Too

A common misconception is that only instances are objects. In reality, classes themselves are also objects.

What Happens When Python Creates a Class?

When Python executes a class definition, it performs these steps internally:
  1. Reads the class statement.
  2. Creates a temporary namespace (dictionary).
  3. Executes every statement inside the class body.
  4. Collects all attributes and methods into the namespace.
  5. Calls type(class_name, bases, namespace).
  6. type creates the new class object.
  7. Assigns the class object to the class name.
When a class inherits from another class, the base classes are passed as the bases argument to type().

Creating a Class Dynamically Using type()

Normally, we define classes statically using the class keyword. However, because classes are objects created by type, you can use the type() function as a constructor to create a class dynamically at runtime. The signature of type() for class creation is:

Example: Static vs. Dynamic Class Creation

Let’s compare the standard static way with the dynamic type() method: 1. The Static Way (Standard):
2. The Dynamic Way (Using type):
Output ?

Every class is an instance of the built-in type class. When you define a class, Python is actually creating a new custom type.
Output:

Class Members vs Instance Members

A class can contain both instance members and class members.

Instance Members

Instance members belong to individual objects. Each object maintains its own copy.
Output ?
Changing one object’s attribute does not affect another object.
Output ?

Class Members

Class members are shared by all objects of a class.
Output ?
Updating the class member affects every object.
Output ?

When Should You Use Class Members?

Use class members when a value is shared by every object. Examples include:
  • Company name
  • College name
  • Tax rate
  • Currency
  • Number of objects created

Exercise 1

Create an Employee class with an instance member name and a class member company. Sample Input
Expected Output

Exercise 2

Create two students and demonstrate that changing an instance member affects only one object. Sample Input
Expected Output

Properties

Properties provide controlled access to attributes while allowing them to be accessed like normal variables. Instead of calling get_name() and set_name(), properties let you write:
using the @property decorator.

Read-only Properties

A property that only defines a getter can be read but not modified.

Write-only Properties

Although Python does not have true write-only variables, a property can emulate one.
This is commonly used for passwords and other sensitive information.

Class Methods

A class method operates on the class itself rather than individual objects. A class method is declared using the @classmethod decorator. Its first parameter is cls, which refers to the class.
Output ?
Class methods are commonly used to:
  • Access or modify class members.
  • Create alternative constructors.
  • Perform operations related to the class.

Alternative Constructor

Output ?

Exercise 1

Create a class method that displays the company name. Sample Input
Expected Output

Exercise 2

Create an alternative constructor that converts a name to title case. Sample Input
Expected Output

Static Methods

A static method belongs to the class but does not access either the class (cls) or the object (self). Static methods are declared using the @staticmethod decorator. They are commonly used for utility functions related to the class.
Output ?
Another example.
Output ?

When Should You Use Static Methods?

Use a static method when:
  • The function is related to the class.
  • It does not use self.
  • It does not use cls.

Exercise 1

Create a static method that checks whether a number is even. Sample Input
Expected Output

Exercise 2

Create a static method that converts Celsius to Fahrenheit. Sample Input
Expected Output

Magic (Dunder) Methods

Magic methods, also known as dunder methods (double underscore methods), are special methods that allow you to customize the behavior of Python objects. They are automatically invoked by Python in response to certain operations such as printing an object, comparing objects, or using operators. Some commonly used magic methods are:

The __str__() Method

By default, printing an object displays its memory location.
Output ?
The __str__() method provides a readable string representation.
Output ?

Exercise 1

Implement __str__() for a Book class. Sample Input
Expected Output

Exercise 2

Implement __str__() for an Employee class. Sample Input
Expected Output

The __repr__() Method

The __repr__() method returns an official string representation of an object. It is mainly intended for developers and debugging.
Output ?

Exercise 1

Implement __repr__() for a Product class. Sample Input
Expected Output

Exercise 2

Implement __repr__() for a Course class. Sample Input
Expected Output

Operator Overloading

Magic methods can also customize the behavior of Python operators.

The __len__() Method

The len() function internally calls __len__().
Output ?

The __eq__() Method

The == operator internally calls __eq__().
Output ?

The __add__() Method

The + operator internally calls __add__().
Output ?

Exercise 1

Implement __len__() for a Library class that returns the number of books. Sample Input
Expected Output

Exercise 2

Implement __add__() for a Wallet class to combine balances. Sample Input
Expected Output

Abstract Base Classes (ABC)

An Abstract Base Class (ABC) defines a common interface that derived classes must implement. Python provides the abc module to create abstract classes.

Why Use ABC?

  • Enforces a common interface.
  • Prevents incomplete implementations.
  • Encourages consistent class design.

Example

Output ?

Exercise 1

Create an abstract class Vehicle with an abstract method start(). Implement it in a Car class.

Exercise 2

Create an abstract class Shape with an abstract method area(). Implement it in a Rectangle class.

What Happens During Inheritance?

When Python creates a derived class, it performs these steps:
  1. Resolves the parent classes.
  2. Validates each base class.
  3. Computes the Method Resolution Order (MRO).
  4. Creates the child class namespace.
  5. Calls type() to create the new class object.
  6. Stores the inheritance hierarchy.
  7. Uses the MRO whenever attributes or methods are searched.

Multiple Inheritance

Python allows a class to inherit from more than one base class.
Output ?

Method Resolution Order (MRO)

When multiple parent classes define the same method, Python follows the Method Resolution Order (MRO) to determine which method to invoke.
Output ?
View the MRO using:
Output ?

Exercise 1

Create a class that inherits from two parent classes and invoke methods from both.

Exercise 2

Print the MRO of a class that inherits from two parent classes.

Best Practices

  • Prefer instance members for object-specific data.
  • Use class members for shared information.
  • Use class methods to work with class-level data.
  • Use static methods for utility functions.
  • Override only the magic methods you actually need.
  • Use abstract base classes to define common interfaces.
  • Keep inheritance hierarchies simple and easy to understand.
  • Avoid deep multiple inheritance unless necessary.

Practice

To reinforce what you’ve learned in this section, practice with the interactive follow-along notebook:

Follow-Along Practice

Practice class/instance variables, class/static methods, custom properties, dunder methods, abstract classes, and multiple inheritance.💻 VS Code | 🚀 Colab | 📥 Download

Summary

In this module, you learned advanced object-oriented programming concepts in Python.

Key Concepts Covered

  • OOP Refresher
  • Class Members vs Instance Members
  • Class Methods
  • Static Methods
  • Magic (Dunder) Methods
  • Operator Overloading
  • Abstract Base Classes (ABC)
  • Multiple Inheritance
  • Method Resolution Order (MRO)
  • Best Practices
These concepts help you design reusable, maintainable, and extensible applications while taking advantage of Python’s powerful object-oriented features.