Python Object-Oriented Programming (OOP) – Complete Notes

Introduction to OOP

What is Object-Oriented Programming?

  • OOP helps map real-world scenarios into code
  • It’s one of the most important topics in any programming language
  • Frequently asked in interviews and used in practical coding

Evolution of Programming Paradigms:

  1. Procedural Programming
    • Sequential code execution
    • Code written line by line in sequence
    • Example: a = 10, b = 20, sum = a + b
  2. Functional Programming
    • Introduced functions for code reusability
    • Reduces redundancy
    • Increases reusability
    • Allows reusing the same code multiple times
  3. Object-Oriented Programming
    • Next level after functional programming
    • Uses objects and classes to reduce redundancy and increase reusability
    • Not mandatory but highly practical and important

Core Concepts

Classes and Objects

Class:

  • A blueprint for creating objects
  • Defines what properties and methods objects will have
  • Example: A student class defines what information every student should have (name, address, roll number)
  • Naming convention: Class names start with a capital letter

Object:

  • An instance of a class
  • The actual implementation created from the blueprint
  • In real world: Everything is an object (mouse, keyboard, pencil)
  • Also called “instances” of a class

Real-World Analogy:

  • Class = School classroom (blueprint)
  • Objects = Individual students sitting in the classroom
  • Class = Car factory blueprint
  • Objects = Individual cars produced

Example:

# Creating a class
class Student:
    name = "Karan"

# Creating objects (instances)
s1 = Student()
s2 = Student()

# Accessing attributes
print(s1.name)  # Output: Karan
print(s2.name)  # Output: Karan

Constructor (__init__)

What is a Constructor?

  • A special function called automatically when an object is created
  • Written as __init__ (init surrounded by double underscores)
  • Always takes self as the first parameter
  • Used for initializing object attributes

Types of Constructors:

  1. Default Constructor:
    • Has only the self parameter
    • Python creates one automatically if not defined
    def __init__(self): print("Adding new student in database")
  2. Parameterized Constructor:
    • Has self plus additional parameters
    • Allows passing values during object creation
    def __init__(self, name, marks): self.name = name self.marks = marks

Example:

class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks

s1 = Student("Karan", 97)
s2 = Student("Arjun", 88)

print(s1.name)   # Output: Karan
print(s1.marks)  # Output: 97
print(s2.name)   # Output: Arjun
print(s2.marks)  # Output: 88

The self Parameter

What is self?

  • A reference to the current instance of the class
  • Points to the object being created
  • Used to access variables and methods belonging to the class
  • Must be the first parameter in all class methods

Note: While self is conventional, you can use any name (like abcd), but it’s best practice to use self for clarity.

Example:

class Student:
    def __init__(self, name):
        self.name = name  # self refers to the current object

s1 = Student("Tony")
# Here, self refers to s1

Attributes

What are Attributes?

  • Data stored inside classes and objects
  • Also called variables or properties

Types of Attributes

1. Instance Attributes (Object Attributes):

  • Different for each object
  • Defined using self.attribute_name
  • Each object has its own copy in memory
  • Examples: name, marks (different for each student)
class Student:
    def __init__(self, name, marks):
        self.name = name      # Instance attribute
        self.marks = marks    # Instance attribute

2. Class Attributes:

  • Common for all objects of the class
  • Shared by all instances
  • Stored only once in memory
  • Defined directly in the class (not in __init__)
class Student:
    college_name = "ABC College"  # Class attribute

    def __init__(self, name, marks):
        self.name = name      # Instance attribute
        self.marks = marks    # Instance attribute

# Accessing class attribute
s1 = Student("Karan", 97)
print(s1.college_name)           # Output: ABC College
print(Student.college_name)      # Output: ABC College

Important: If both class and instance attributes have the same name, instance attributes get higher priority.


Methods

What are Methods?

  • Functions that belong to objects
  • Defined inside a class
  • Always take self as the first parameter (except static methods)

Example:

class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks

    def welcome(self):
        print("Welcome Student", self.name)

    def get_marks(self):
        return self.marks

# Using methods
s1 = Student("Karan", 97)
s1.welcome()              # Output: Welcome Student Karan
print(s1.get_marks())     # Output: 97

Static Methods

What are Static Methods?

  • Methods that don’t use the self parameter
  • Work at class level, not object level
  • Defined using the @staticmethod decorator
  • Don’t need object-specific data

Example:

class Student:
    @staticmethod
    def hello():
        print("Hello")

s1 = Student()
s1.hello()  # Output: Hello

Decorator: A special function that modifies the behavior of another function.


Four Pillars of OOP

1. Abstraction

Definition:

  • Hiding implementation details of a class
  • Showing only essential features to the user
  • Hiding unnecessary complexity

Real-World Example:

  • When driving a car, you don’t see what’s happening inside the engine
  • You only interact with steering, accelerator, and brakes
  • Internal combustion process is hidden (abstracted)

Code Example:

class Car:
    def __init__(self):
        self.acc = False
        self.brk = False
        self.clutch = False

    def start(self):
        self.clutch = True
        self.acc = True
        print("Car started")

car1 = Car()
car1.start()  # User doesn't see internal steps, only the result

2. Encapsulation

Definition:

  • Wrapping data and related functions into a single unit (class)
  • Creating a “capsule” of data and methods
  • What we’ve been doing throughout this chapter

Example:

class Student:
    def __init__(self, name, marks):
        self.name = name       # Data
        self.marks = marks     # Data

    def get_marks(self):       # Related function
        return self.marks

The class encapsulates both data (name, marks) and methods (get_marks) together.


Practice Example: Bank Account System

class Account:
    def __init__(self, balance, account_number):
        self.balance = balance
        self.account_number = account_number

    def debit(self, amount):
        self.balance -= amount
        print("Rs.", amount, "was debited")
        print("Total balance is", self.get_balance())

    def credit(self, amount):
        self.balance += amount
        print("Rs.", amount, "was credited")
        print("Total balance is", self.get_balance())

    def get_balance(self):
        return self.balance

# Creating an account
acc1 = Account(10000, "12345")

# Performing transactions
acc1.debit(1000)    # Balance becomes 9000
acc1.credit(500)    # Balance becomes 9500
acc1.credit(40000)  # Salary credited, balance becomes 49500
acc1.debit(10000)   # Rent paid, balance becomes 39500

Practice Example: Student Average Calculator

class Student:
    def __init__(self, name, marks):
        self.name = name
        self.marks = marks  # marks is a list

    def get_average(self):
        sum = 0
        for val in self.marks:
            sum += val
        print("Hi", self.name, "your average score is", sum/3)

# Creating student
s1 = Student("Tony Stark", [99, 98, 97])
s1.get_average()  # Output: Hi Tony Stark your average score is 98.0

# Modifying attributes
s1.name = "Iron Man"
s1.get_average()  # Output: Hi Iron Man your average score is 98.0

Key Takeaways

  1. Classes are blueprints; Objects are instances created from blueprints
  2. Constructor (__init__) initializes objects automatically
  3. self refers to the current object instance
  4. Instance attributes are different for each object
  5. Class attributes are shared by all objects
  6. Methods are functions inside classes (always have self as first parameter)
  7. Static methods don’t use self and work at class level
  8. Abstraction = hiding implementation details
  9. Encapsulation = wrapping data and methods together
  10. OOP helps organize code in a logical, structured manner for real-world scenarios

Important Notes

  • In Python, many built-in data types are actually classes:
    • Lists are objects
    • Strings are objects
    • Dictionaries are objects
  • Using classes is not mandatory, but it’s:
    • Very practical for complex projects
    • Important for interviews
    • Essential for becoming a good developer
  • Classes help avoid confusion when managing multiple related pieces of data
  • Objects occupy space in memory
  • Multiple objects of the same class can exist, each with different attribute values

Topics to be Covered in Part 2

  • Inheritance
  • Polymorphism
  • Private attributes and methods
  • Deleting attributes
  • And more advanced OOP concepts

Remember: Practice is key to mastering OOP concepts!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top