#1 Data Analytics Program in India
₹2,499₹1,499Enroll Now
8 min read
•Question 18 of 41medium

Object-Oriented Programming

Classes and objects in Python.

What You'll Learn

  • Classes, objects, and instances
  • Instance vs class attributes
  • Methods: instance, class, and static
  • Properties and encapsulation
  • Magic/dunder methods

Understanding OOP in Python

Object-Oriented Programming (OOP) organizes code into objects that combine data (attributes) and behavior (methods). Python's OOP is flexible and powerful.

Key concepts:

  • Class: Blueprint for creating objects
  • Object/Instance: A specific realization of a class
  • Attribute: Data stored in an object
  • Method: Function defined in a class

Defining Classes

code.pyPython
class Person:
    # Class attribute (shared by all instances)
    species = "Human"

    # Constructor (initializer)
    def __init__(self, name, age):
        # Instance attributes (unique to each instance)
        self.name = name
        self.age = age

    # Instance method
    def greet(self):
        return f"Hello, I'm {self.name}"

    # String representation
    def __str__(self):
        return f"Person({self.name}, {self.age})"

    def __repr__(self):
        return f"Person('{self.name}', {self.age})"

# Creating objects (instances)
alice = Person("Alice", 30)
bob = Person("Bob", 25)

print(alice.greet())     # "Hello, I'm Alice"
print(alice.species)     # "Human"
print(Person.species)    # "Human"

Instance vs Class Attributes

code.pyPython
class Dog:
    # Class attribute
    species = "Canis familiaris"
    count = 0

    def __init__(self, name):
        # Instance attribute
        self.name = name
        Dog.count += 1  # Modify class attribute

dog1 = Dog("Buddy")
dog2 = Dog("Max")

print(dog1.name)    # "Buddy" (instance)
print(dog2.name)    # "Max" (instance)
print(Dog.count)    # 2 (class)
print(dog1.count)   # 2 (accessed via instance)

Method Types

code.pyPython
class MyClass:
    class_var = 0

    def __init__(self, value):
        self.value = value

    # Instance method - needs self, can access instance and class
    def instance_method(self):
        return f"Instance value: {self.value}"

    # Class method - needs cls, can access class but not instance
    @classmethod
    def class_method(cls):
        return f"Class var: {cls.class_var}"

    # Static method - no self/cls, utility function
    @staticmethod
    def static_method(x, y):
        return x + y

    # Alternative constructor (common classmethod use)
    @classmethod
    def from_string(cls, data_string):
        value = int(data_string)
        return cls(value)

obj = MyClass(10)
print(obj.instance_method())      # "Instance value: 10"
print(MyClass.class_method())     # "Class var: 0"
print(MyClass.static_method(2,3)) # 5

Properties (Getters/Setters)

code.pyPython
class Temperature:
    def __init__(self, celsius=0):
        self._celsius = celsius

    @property
    def celsius(self):
        """Get temperature in Celsius."""
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        """Set temperature with validation."""
        if value < -273.15:
            raise ValueError("Below absolute zero!")
        self._celsius = value

    @property
    def fahrenheit(self):
        """Computed property."""
        return self._celsius * 9/5 + 32

temp = Temperature(25)
print(temp.celsius)      # 25
print(temp.fahrenheit)   # 77.0
temp.celsius = 30        # Uses setter
# temp.celsius = -300    # ValueError!

Encapsulation (Access Control)

code.pyPython
class BankAccount:
    def __init__(self, balance):
        self.public = "Anyone can access"    # Public
        self._protected = "Convention only"   # Protected (convention)
        self.__private = balance              # Private (name mangling)

    def get_balance(self):
        return self.__private

account = BankAccount(1000)
print(account.public)       # Works
print(account._protected)   # Works (but shouldn't)
# print(account.__private)  # AttributeError!
print(account._BankAccount__private)  # Works (name mangling)

Magic/Dunder Methods

code.pyPython
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"Vector({self.x}, {self.y})"

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __len__(self):
        return int((self.x**2 + self.y**2)**0.5)

v1 = Vector(2, 3)
v2 = Vector(4, 5)
v3 = v1 + v2         # Uses __add__
print(v3)            # Vector(6, 8)
print(v1 == v2)      # False

Common Magic Methods

MethodPurpose
__init__Constructor
__str__String for print()
__repr__Official string representation
__eq__Equality (==)
__lt__, __gt__Comparison (<, >)
__add__, __sub__Arithmetic (+, -)
__len__len() function
__getitem__Indexing ([])
__iter__Iteration
__call__Make instance callable

Interview Tip

When asked about Python OOP:

  1. __init__ is constructor, self is instance reference
  2. Class vs instance attributes (shared vs unique)
  3. @property for getters/setters
  4. @classmethod takes cls, @staticmethod takes neither
  5. _ is convention for protected, __ triggers name mangling
  6. Know common dunder methods