Object-Oriented Programming (OOP)
Master OOP in Python. Learn inheritance, polymorphism, double underscore methods, property decorators, and classes.
Downloaded from PrepIQ (https://prepiq.online)
Q1. What is Object-Oriented Programming (OOP) and what are its 4 pillars?
OOP is a programming paradigm based on objects and classes. The 4 pillars of OOP are: Encapsulation, Inheritance, Polymorphism, and Abstraction.
| Pillar | Description | Example |
|---|---|---|
| Encapsulation | Bundling data and methods, hiding internal details | Private variables with getters/setters |
| Inheritance | Derive new classes from existing ones | class Dog(Animal): pass |
| Polymorphism | Objects behave differently based on type | Method overriding, duck typing |
| Abstraction | Hide complexity, show only essential features | Abstract classes, interfaces |
# Encapsulation - hiding internal details
class BankAccount:
def __init__(self, balance):
self.__balance = balance # Private
def deposit(self, amount):
self.__balance += amount
def get_balance(self):
return self.__balance
# Inheritance - reusing code
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
return 'Woof!'
# Polymorphism - same method, different behavior
dog = Dog()
cat = Cat()
print(dog.speak()) # Woof!
print(cat.speak()) # Meow!
# Abstraction - hide complexity
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
Q2. What is the difference between a class and an object?
| Aspect | Class | Object |
|---|---|---|
| Definition | Blueprint/template | Instance of class |
| Type | Logical entity | Physical entity |
| Created | Once during coding | Multiple times at runtime |
| Memory | No memory allocated | Memory allocated when created |
| Example | class Car | car1 = Car() |
class Car:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def drive(self):
return f'{self.brand} {self.model} is driving'
# Class is template, object is instance
car1 = Car('Toyota', 'Camry') # Object 1
car2 = Car('Honda', 'Civic') # Object 2
print(car1.drive()) # Toyota Camry is driving
print(car2.drive()) # Honda Civic is driving
# Check type
print(type(car1)) # <class '__main__.Car'>
print(isinstance(car1, Car)) # True
Q3. What are constructors and destructors in Python?
class Person:
def __init__(self, name, age):
print('Constructor called')
self.name = name
self.age = age
def __del__(self):
print(f'Destructor called for {self.name}')
# Constructor is called when object is created
person = Person('John', 30) # Constructor called
del person # Destructor called
# init vs new
class MyClass:
def __new__(cls):
print('__new__ called - create instance')
return super().__new__(cls)
def __init__(self):
print('__init__ called - initialize instance')
obj = MyClass()
# Output:
# __new__ called - create instance
# __init__ called - initialize instance
Q4. What are the different types of inheritance?
| Type | Description | Example |
|---|---|---|
| Single | One parent, one child | class Dog(Animal) |
| Multiple | Multiple parents, one child | class Car(Vehicle, Fuel) |
| Multilevel | Chain: A->B->C | class Puppy(Dog(Animal)) |
| Hierarchical | One parent, multiple children | Dog, Cat, Bird from Animal |
| Hybrid | Combination of types | Mix of above types |
# Single Inheritance
class Animal:
pass
class Dog(Animal):
pass
# Multiple Inheritance
class Vehicle:
pass
class Fuel:
pass
class Car(Vehicle, Fuel):
pass
# Multilevel Inheritance
class Animal:
pass
class Dog(Animal):
pass
class Puppy(Dog):
pass
# Hierarchical Inheritance
class Animal:
pass
class Dog(Animal):
pass
class Cat(Animal):
pass
class Bird(Animal):
pass
# Diamond Problem (with Multiple Inheritance)
class A:
def method(self):
print('A method')
class B(A):
def method(self):
print('B method')
class C(A):
def method(self):
print('C method')
class D(B, C):
pass
d = D()
d.method() # B method (C3 Linearization)
print(D.__mro__) # Shows MRO
Q5. What is inheritance and how does it work in Python?
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f'{self.name} makes sound')
class Dog(Animal):
def speak(self):
print(f'{self.name} barks: Woof!')
class Cat(Animal):
def speak(self):
print(f'{self.name} meows: Meow!')
# Creating objects
dog = Dog('Buddy')
cat = Cat('Whiskers')
dog.speak() # Buddy barks: Woof!
cat.speak() # Whiskers meows: Meow!
# Method Resolution Order (MRO)
print(Dog.__mro__) # Shows inheritance chain
# super() to call parent methods
class Vehicle:
def __init__(self, brand):
self.brand = brand
class Car(Vehicle):
def __init__(self, brand, model):
super().__init__(brand) # Call parent constructor
self.model = model
car = Car('Toyota', 'Camry')
print(car.brand) # Toyota
print(car.model) # Camry
Q6. What is polymorphism and how does it work?
# Method Overriding (Compile-time Polymorphism)
class Shape:
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
# Polymorphic behavior
shapes = [Circle(5), Rectangle(4, 6)]
for shape in shapes:
print(shape.area()) # Different implementation
# Duck Typing (Runtime Polymorphism)
class Dog:
def sound(self):
return 'Woof!'
class Cat:
def sound(self):
return 'Meow!'
class Bird:
def sound(self):
return 'Tweet!'
def animal_sound(animal):
print(animal.sound())
animal_sound(Dog()) # Woof!
animal_sound(Cat()) # Meow!
animal_sound(Bird()) # Tweet!
# Operator Overloading
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __str__(self):
return f'({self.x}, {self.y})'
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2 # Uses __add__
print(v3) # (4, 6)
Q7. What is encapsulation and how do you achieve it?
class BankAccount:
def __init__(self, balance):
self.__balance = balance # Private (double underscore)
def deposit(self, amount):
if amount > 0:
self.__balance += amount
return f'Deposited {amount}'
return 'Invalid amount'
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
return f'Withdrawn {amount}'
return 'Insufficient funds'
def get_balance(self):
return self.__balance
@property
def balance(self):
return self.__balance
# Using encapsulation
account = BankAccount(1000)
print(account.deposit(500)) # Deposited 500
print(account.withdraw(200)) # Withdrawn 200
print(account.get_balance()) # 1300
# Can't access directly
# print(account.__balance) # AttributeError
# Single underscore (convention, not enforced)
class MyClass:
def __init__(self):
self._protected = 'Protected' # Convention
self.__private = 'Private' # Name mangling
def __private_method(self):
return 'Private method'
obj = MyClass()
print(obj._protected) # Accessible (convention)
# obj._MyClass__private # Name mangling
Q8. What is abstraction and how do you implement it?
from abc import ABC, abstractmethod
# Abstract class
class Vehicle(ABC):
@abstractmethod
def start(self):
pass
@abstractmethod
def stop(self):
pass
def info(self):
print('This is a vehicle') # Concrete method
# Concrete implementation
class Car(Vehicle):
def start(self):
return 'Car started'
def stop(self):
return 'Car stopped'
class Bike(Vehicle):
def start(self):
return 'Bike started'
def stop(self):
return 'Bike stopped'
# Using abstract class
vehicles = [Car(), Bike()]
for vehicle in vehicles:
print(vehicle.start())
vehicle.info()
print(vehicle.stop())
# Can't instantiate abstract class
# v = Vehicle() # TypeError
# Abstract properties
class Shape(ABC):
@property
@abstractmethod
def area(self):
pass
class Square(Shape):
def __init__(self, side):
self._side = side
@property
def area(self):
return self._side ** 2
Q9. What are class methods and static methods?
| Type | Decorator | Receives | Use Case |
|---|---|---|---|
| Instance | @property | self | Instance data |
| Class Method | @classmethod | cls | Class data |
| Static Method | @staticmethod | None | Utility functions |
class MyClass:
class_var = 0
def __init__(self, value):
self.value = value
MyClass.class_var += 1
# Instance method
def instance_method(self):
return f'Value: {self.value}'
# Class method
@classmethod
def from_string(cls, string):
value = int(string)
return cls(value)
@classmethod
def get_count(cls):
return cls.class_var
# Static method
@staticmethod
def is_positive(num):
return num > 0
@staticmethod
def multiply(a, b):
return a * b
# Using class method
obj = MyClass.from_string('10')
print(MyClass.get_count()) # 1
# Using static method
print(MyClass.is_positive(5)) # True
print(MyClass.multiply(3, 4)) # 12
# Static method - no access to self or cls
class Math:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def subtract(a, b):
return a - b
print(Math.add(5, 3)) # 8
print(Math.subtract(5, 3)) # 2
Q10. What is method overriding and method overloading?
# Method Overriding - same method name, different implementation
class Parent:
def method(self):
print('Parent method')
class Child(Parent):
def method(self):
print('Child method')
super().method() # Call parent
child = Child()
child.method()
# Output:
# Child method
# Parent method
# Method Overloading - Python doesn't support like Java
# But can achieve with default arguments or *args
class Calculator:
# Using default arguments
def add(self, a, b, c=0):
return a + b + c
print(Calculator().add(2, 3)) # 5
print(Calculator().add(2, 3, 4)) # 9
# Using *args
def multiply(self, *args):
result = 1
for num in args:
result *= num
return result
print(Calculator().multiply(2, 3)) # 6
print(Calculator().multiply(2, 3, 4)) # 24
# Using type checking
def process(self, data):
if isinstance(data, int):
return data * 2
elif isinstance(data, str):
return data.upper()
elif isinstance(data, list):
return len(data)
# Operator Overloading
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __sub__(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 __str__(self):
return f'({self.x}, {self.y})'
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # (4, 6)
print(v1 == v2) # False
Object-Oriented Programming (OOP)
Master OOP in Python. Learn inheritance, polymorphism, double underscore methods, property decorators, and classes.
What is Object-Oriented Programming (OOP) and what are its 4 pillars?
OOP is a programming paradigm based on objects and classes. The 4 pillars of OOP are: Encapsulation, Inheritan...
What is the difference between a class and an object?
AspectClassObjectDefinitionBlueprint/templateInstance of classTypeLogical entityPhysical entityCreatedOnce dur...
What are constructors and destructors in Python?
class Person: def __init__(self, name, age): print('Constructor called') self.name = name...
What are the different types of inheritance?
TypeDescriptionExampleSingleOne parent, one childclass Dog(Animal)MultipleMultiple parents, one childclass Car...
What is inheritance and how does it work in Python?
class Animal: def __init__(self, name): self.name = name def speak(self): print(f...
What is polymorphism and how does it work?
# Method Overriding (Compile-time Polymorphism) class Shape: def area(self): pass class Circle(Sh...
What is encapsulation and how do you achieve it?
class BankAccount: def __init__(self, balance): self.__balance = balance # Private (double unders...
What is abstraction and how do you implement it?
from abc import ABC, abstractmethod # Abstract class class Vehicle(ABC): @abstractmethod def start(se...
What are class methods and static methods?
TypeDecoratorReceivesUse CaseInstance@propertyselfInstance dataClass Method@classmethodclsClass dataStatic Met...
What is method overriding and method overloading?
# Method Overriding - same method name, different implementation class Parent: def method(self): p...