CS Engineering Gyan

Object-Oriented Programming in Python

In the previous chapter, we looked at Functions and how they let a program organise code into reusable, named blocks. Object-Oriented Programming, commonly abbreviated as OOP, takes this idea of organisation a step further by grouping related data and the functions that operate on that data together into a single unit, instead of keeping variables and functions scattered separately throughout a program. This chapter introduces the core ideas behind Object-Oriented Programming in Python: classes, objects, and the four principles that define how object-oriented code is typically structured.

As programs grow larger and start modelling real-world things, such as a user, a bank account, or in keeping with the examples used throughout this series, a YouTube channel, it becomes increasingly useful to bundle a thing's properties, like its name or subscriber count, together with the actions it can perform, like uploading a video or gaining subscribers. Object-Oriented Programming provides exactly this kind of structure, and Python fully supports it as one of its core programming styles.


What is Object-Oriented Programming?

Object-Oriented Programming is a style of programming built around the idea of organising code into classes and objects. A class acts as a blueprint describing what properties and behaviours something should have, while an object is an actual, individual instance created from that blueprint. This approach makes it easier to model real-world entities in code, keeps related data and functionality bundled together in one place, and makes larger programs considerably easier to organise, extend, and maintain over time.


Class and Object

A class is defined using the class keyword, and it describes the properties, known as attributes, and the functions, known as methods, that any object created from that class will have. An object is a specific instance of a class, created by calling the class name as though it were a function. A single class can be used to create as many separate objects as needed, each with its own independent set of attribute values.

Example

class YouTubeChannel:
    def show_intro(self):
        print("This is a YouTube channel object.")

channel1 = YouTubeChannel()
channel1.show_intro()

Output

This is a YouTube channel object.

Here, YouTubeChannel is a class acting as a blueprint, and channel1 is an object created from that class, capable of calling the show_intro method defined inside it.


The __init__ Constructor and the self Keyword

When an object is created from a class, Python automatically calls a special method named __init__, if one has been defined, allowing the object's initial attribute values to be set up right at the moment it's created. Every method defined inside a class, including __init__, includes self as its first parameter, which refers to the specific object the method is currently being called on, allowing that method to access and modify that particular object's own attributes.

Example

class YouTubeChannel:
    def __init__(self, name, subscribers):
        self.name = name
        self.subscribers = subscribers

    def show_details(self):
        print(self.name, "has", self.subscribers, "subscribers.")

channel1 = YouTubeChannel("CS Engineering Gyan", 45000)
channel1.show_details()

Output

CS Engineering Gyan has 45000 subscribers.

Here, the __init__ method runs automatically as soon as channel1 is created, storing the values "CS Engineering Gyan" and 45000 as attributes on that specific object using self.


The Four Pillars of Object-Oriented Programming

Object-Oriented Programming is generally described in terms of four core principles: Encapsulation, Inheritance, Polymorphism, and Abstraction. Each of these principles addresses a different aspect of how object-oriented code is structured and behaves, and together they form the foundation of writing clean, well-organised, object-oriented Python programs.

Encapsulation

Encapsulation refers to bundling an object's data, its attributes, together with the methods that operate on that data, inside a single class, while also controlling how that data can actually be accessed or modified from outside the class. In Python, a naming convention using a leading underscore is commonly used to indicate that an attribute is intended to be treated as internal to the class, discouraging direct access from outside code in favour of using the class's own methods instead.

Example

class YouTubeChannel:
    def __init__(self, name, subscribers):
        self.name = name
        self._subscribers = subscribers

    def gain_subscribers(self, count):
        self._subscribers += count

    def show_subscribers(self):
        print(self.name, "subscriber count:", self._subscribers)

channel1 = YouTubeChannel("CS Engineering Gyan", 45000)
channel1.gain_subscribers(500)
channel1.show_subscribers()

Output

CS Engineering Gyan subscriber count: 45500

Here, the subscriber count is only ever updated through the gain_subscribers method, rather than being changed directly from outside the class, keeping that logic bundled together and controlled in one place.

Inheritance

Inheritance allows a new class, known as a child or derived class, to reuse the attributes and methods already defined in an existing class, known as a parent or base class, instead of rewriting that same logic again from scratch. The child class can also add its own additional attributes and methods, or override existing ones, on top of everything it already inherits from the parent class.

Example

class YouTubeChannel:
    def __init__(self, name, subscribers):
        self.name = name
        self.subscribers = subscribers

    def show_details(self):
        print(self.name, "has", self.subscribers, "subscribers.")

class EducationChannel(YouTubeChannel):
    def __init__(self, name, subscribers, subject):
        super().__init__(name, subscribers)
        self.subject = subject

    def show_subject(self):
        print(self.name, "primarily teaches", self.subject)

channel1 = EducationChannel("CS Engineering Gyan", 45000, "Computer Science")
channel1.show_details()
channel1.show_subject()

Output

CS Engineering Gyan has 45000 subscribers.
CS Engineering Gyan primarily teaches Computer Science

Here, EducationChannel inherits from YouTubeChannel, automatically gaining access to the show_details method, while also adding its own new attribute, subject, and its own new method, show_subject.

Polymorphism

Polymorphism allows different classes to define a method with the exact same name, while each class provides its own specific implementation of what that method actually does. This means the same method call can behave differently depending on which particular object it's actually being called on, without the calling code needing to know or care exactly which class that object belongs to.

Example

class EducationChannel:
    def describe(self):
        print("This channel focuses on educational content.")

class EntertainmentChannel:
    def describe(self):
        print("This channel focuses on entertainment content.")

channels = [EducationChannel(), EntertainmentChannel()]

for channel in channels:
    channel.describe()

Output

This channel focuses on educational content.
This channel focuses on entertainment content.

Here, both classes define a method called describe, but each one produces a different result, and the same loop is able to call describe() on every object in the list without needing to know in advance which specific class each object belongs to.

Abstraction

Abstraction involves exposing only the essential details a user of a class actually needs to interact with it, while hiding the more complex internal implementation details behind that simpler interface. A method can be called without its user needing to understand exactly how it works internally, only what it does and what result it produces.

Example

class YouTubeChannel:
    def __init__(self, name, subscribers):
        self.name = name
        self.subscribers = subscribers

    def _calculate_growth_bonus(self):
        return self.subscribers * 0.02

    def show_growth_bonus(self):
        bonus = self._calculate_growth_bonus()
        print(self.name, "estimated monthly growth:", bonus)

channel1 = YouTubeChannel("CS Engineering Gyan", 45000)
channel1.show_growth_bonus()

Output

CS Engineering Gyan estimated monthly growth: 900.0

Here, calling show_growth_bonus() is all a user of this class actually needs to do; the underlying calculation performed inside _calculate_growth_bonus remains hidden away as an internal implementation detail they don't need to worry about.


Comparison of the Four Pillars of OOP

Principle What It Achieves
Encapsulation Bundles data and methods together, controlling how data is accessed or modified
Inheritance Allows a class to reuse and extend the attributes and methods of another class
Polymorphism Lets the same method name behave differently depending on the object it's called on
Abstraction Hides complex implementation details behind a simpler, easier-to-use interface

Best Practices While Learning OOP in Python


Common Mistakes Beginners Make

Mistake Correct Practice
Forgetting to include self as a method's first parameter. Every method inside a class needs self as its first parameter to access that object's own attributes.
Confusing a class with an object. A class is the blueprint; an object is an actual instance created from that blueprint using the class name.
Assuming inheritance means copying and pasting code between classes. Inheritance lets a child class automatically reuse a parent class's attributes and methods without duplicating any code.
Mixing up polymorphism with simply having multiple classes. Polymorphism specifically refers to different classes implementing a method with the same name differently.

Frequently Asked Interview Questions

  1. What is the difference between a class and an object?
    A class is a blueprint describing the attributes and methods something should have, while an object is an actual instance created from that class.
  2. What is the purpose of the __init__ method in Python?
    The __init__ method runs automatically when an object is created, allowing that object's initial attribute values to be set up.
  3. Why does every method inside a class include self as a parameter?
    Because self refers to the specific object the method is being called on, allowing the method to access and modify that object's own attributes.
  4. What is the difference between Inheritance and Polymorphism?
    Inheritance allows a class to reuse and extend the attributes and methods of another class, while Polymorphism allows different classes to implement a method with the same name in different ways.
  5. How does Encapsulation help with writing reliable code?
    By bundling data together with the methods that operate on it and controlling direct access to that data, Encapsulation reduces the chances of that data being changed in unexpected or inconsistent ways.
  6. What does Abstraction actually hide from a class's user?
    Abstraction hides the complex internal implementation details of how a method works, exposing only the simpler interface a user actually needs to interact with.
  7. Can a single class be used to create multiple objects?
    Yes, a single class can be used to create as many separate objects as needed, each maintaining its own independent set of attribute values.

Summary

Object-Oriented Programming lets a Python program organise data and behaviour together into classes and objects, rather than keeping them scattered separately throughout the code. We looked at how to define a class and create objects from it, how the __init__ constructor and the self keyword work together to set up an object's attributes, and the four pillars of OOP — Encapsulation, Inheritance, Polymorphism, and Abstraction — each contributing a different way of keeping object-oriented code organised, reusable, and easy to work with.

With a solid understanding of how classes and objects work in Python, you are now ready to move on to file handling, which explains how a Python program can read from and write to files stored outside the program itself.


← Previous: Functions in Python Next: File Handling →

Home Visit Our YouTube Channel