Exercise Solutions Available
Step-by-step answers for all textbook questions in this chapter
How to Use This Page
1. Attempt every exercise on your own before reading the solution. 2. Compare your approach with the solution — focus on the logic, not just the final answer. 3. Type and run the Python code on your computer; reading alone is not enough. 4. Review the Common Mistakes section to avoid errors that cost marks in exams.
Key Concepts
| Concept | Syntax / Description |
|---|---|
| Class | Blueprint for creating objects: class ClassName: |
| Object | Instance of a class: obj = ClassName() |
__init__ | Constructor method — runs automatically when object is created |
self | Reference to the current instance — first parameter of instance methods |
| Instance variable | Unique to each object: self.var = value |
| Class variable | Shared by all objects: defined in class body |
| Instance method | Operates on instance data: def method(self): |
| Class method | Operates on class data: @classmethod def method(cls): |
| Static method | Independent of instance/class: @staticmethod def method(): |
| Inheritance | Child class inherits from parent: class Child(Parent): |
super() | Calls parent class methods |
__str__ | Returns user-friendly string (used by print()) |
__repr__ | Returns developer-friendly string (used by repr()) |
Multiple Choice Questions (MCQs)
Q1. Which method is called automatically when an object is created?
- (a)
__new__ - (b)
__init__ - (c)
__create__ - (d)
__start__
Q2. What does the self parameter refer to in a class method?
- (a) The class itself
- (b) The parent class
- (c) The current instance of the class
- (d) A global variable
Q3. Which of the following is a class variable?
- (a)
self.name = "Arun" - (b)
name = "Arun"(defined directly in the class body) - (c)
obj.name = "Arun" - (d)
def name(self):
Q4. In single inheritance, if class B inherits from class A, which statement is true?
- (a) B can access only its own methods
- (b) B can access methods of A as well as its own
- (c) A can access methods of B
- (d) B cannot add new methods
Q5. What does super().__init__() do?
- (a) Creates a new object
- (b) Calls the parent class constructor
- (c) Deletes the parent class
- (d) Overrides the current class
Fill in the Blanks
Q1. A ______ is a blueprint, and an ______ is an instance created from it.
Q2. The ______ method is the constructor that initializes an object's attributes.
Q3. Variables defined with self inside __init__ are called ______ variables.
Q4. A ______ method uses @classmethod decorator and takes cls as the first parameter.
Q5. When a child class redefines a method from the parent class, it is called method ______.
True or False
Q1. A class can have only one __init__ method.
Q2. self is a keyword in Python.
Q3. A static method can access instance variables directly.
Q4. In inheritance, a child class can access private members of the parent class.
Q5. __str__ is called by the print() function.
Match the Following
| Column A | Column B |
|---|---|
1. __init__ | (a) Blueprint for objects |
2. self | (b) Calls parent class method |
| 3. Class | (c) Constructor method |
4. super() | (d) Reference to current instance |
5. @staticmethod | (e) Method independent of instance/class |
Short Answer Questions
Q1. What is a class? What is an object? How are they related?
A class is a blueprint or template that defines the attributes and methods common to all objects of that type. An object is a specific instance created from a class.
class Car: # Class (blueprint)
def __init__(self, brand, color):
self.brand = brand # Instance variable
self.color = color
c1 = Car("Honda", "Red") # Object (instance)
c2 = Car("Toyota", "Blue") # Another object
print(c1.brand) # Honda
print(c2.color) # Blue
Each object has its own copy of instance variables but shares the class definition.
Q2. Explain the __init__ method with an example.
__init__ is the constructor method. It is called automatically when a new object is created and is used to initialize the object's attributes.
class Student:
def __init__(self, name, roll_no, marks):
self.name = name
self.roll_no = roll_no
self.marks = marks
def display(self):
print(f"Name: {self.name}, Roll: {self.roll_no}, Marks: {self.marks}")
s = Student("Arun", 101, 95) # __init__ is called automatically
s.display()
# Output: Name: Arun, Roll: 101, Marks: 95
Q3. Differentiate between instance variables and class variables.
| Feature | Instance Variable | Class Variable |
|---|---|---|
| Defined in | Inside __init__ using self | Directly in class body |
| Scope | Unique to each object | Shared by all objects |
| Access | self.var or obj.var | ClassName.var or self.var |
| Change | Affects only that object | Affects all objects (if changed via class) |
class Student:
school = "KV" # Class variable (shared)
def __init__(self, name):
self.name = name # Instance variable (unique)
s1 = Student("Arun")
s2 = Student("Bala")
print(s1.school) # KV (shared)
print(s2.school) # KV (shared)
Student.school = "DPS"
print(s1.school) # DPS (changed for all)
Q4. Differentiate between instance method, class method, and static method.
| Feature | Instance Method | Class Method | Static Method |
|---|---|---|---|
| Decorator | None | @classmethod | @staticmethod |
| First param | self | cls | None |
| Access instance data? | Yes | No | No |
| Access class data? | Yes | Yes | No |
| Call via | obj.method() | ClassName.method() or obj.method() | ClassName.method() or obj.method() |
class MyClass:
count = 0 # class variable
def __init__(self):
MyClass.count += 1
def instance_method(self):
return f"Instance method: self.data"
@classmethod
def class_method(cls):
return f"Class method: count={cls.count}"
@staticmethod
def static_method():
return "Static method: no self or cls"
obj = MyClass()
print(obj.instance_method()) # Instance method
print(MyClass.class_method()) # Class method: count=1
print(MyClass.static_method()) # Static method
Q5. What is inheritance? Give an example.
Inheritance allows a child class to acquire properties and methods from a parent class, promoting code reuse.
class Animal: # Parent class
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
class Dog(Animal): # Child class
def speak(self): # Method overriding
return f"{self.name} barks"
class Cat(Animal): # Child class
def speak(self):
return f"{self.name} meows"
d = Dog("Rex")
c = Cat("Whiskers")
print(d.speak()) # Rex barks
print(c.speak()) # Whiskers meows
Detailed Answers
Q1. Write a Python program to create a Student class with __init__, display, and grade calculation methods.
class Student:
def __init__(self, name, roll_no, marks):
"""Constructor to initialize student details."""
self.name = name
self.roll_no = roll_no
self.marks = marks # marks is a list of subject marks
def display(self):
"""Display student information."""
print(f"Name: {self.name}")
print(f"Roll No: {self.roll_no}")
print(f"Marks: {self.marks}")
def total(self):
"""Calculate total marks."""
return sum(self.marks)
def average(self):
"""Calculate average marks."""
return self.total() / len(self.marks)
def grade(self):
"""Determine grade based on average."""
avg = self.average()
if avg >= 90:
return "A+"
elif avg >= 75:
return "A"
elif avg >= 60:
return "B"
elif avg >= 50:
return "C"
else:
return "D"
def __str__(self):
return f"Student({self.name}, Roll:{self.roll_no}, Grade:{self.grade()})"
# Creating objects
s1 = Student("Arun", 101, [85, 90, 78, 92, 88])
s2 = Student("Bala", 102, [55, 62, 48, 70, 65])
for s in [s1, s2]:
s.display()
print(f"Total: {s.total()}")
print(f"Average: {s.average():.2f}")
print(f"Grade: {s.grade()}")
print(f"String: {s}")
print("---")
Q2. Demonstrate inheritance with a parent class Employee and child classes Manager and Developer.
class Employee:
company = "TechCorp" # Class variable
def __init__(self, name, emp_id, salary):
self.name = name
self.emp_id = emp_id
self.salary = salary
def display(self):
print(f"Name: {self.name}, ID: {self.emp_id}, Salary: ₹{self.salary}")
def annual_salary(self):
return self.salary * 12
class Manager(Employee):
def __init__(self, name, emp_id, salary, team_size):
super().__init__(name, emp_id, salary) # Call parent constructor
self.team_size = team_size
def display(self):
super().display() # Call parent display
print(f"Role: Manager, Team Size: {self.team_size}")
def bonus(self):
return self.salary * 0.2 # 20% bonus
class Developer(Employee):
def __init__(self, name, emp_id, salary, language):
super().__init__(name, emp_id, salary)
self.language = language
def display(self):
super().display()
print(f"Role: Developer, Language: {self.language}")
def bonus(self):
return self.salary * 0.1 # 10% bonus
# Creating objects
m = Manager("Priya", "M101", 80000, 8)
d = Developer("Kumar", "D201", 60000, "Python")
m.display()
print(f"Annual Salary: ₹{m.annual_salary()}")
print(f"Bonus: ₹{m.bonus()}")
print("---")
d.display()
print(f"Annual Salary: ₹{d.annual_salary()}")
print(f"Bonus: ₹{d.bonus()}")
Q3. Write a program to demonstrate __str__ and __repr__ methods.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
"""User-friendly string representation."""
return f"Point({self.x}, {self.y})"
def __repr__(self):
"""Developer-friendly string representation."""
return f"Point(x={self.x}, y={self.y})"
p = Point(3, 5)
# __str__ is called by print() and str()
print(p) # Point(3, 5)
print(str(p)) # Point(3, 5)
# __repr__ is called by repr() and in the interactive shell
print(repr(p)) # Point(x=3, y=5)
# When only __repr__ is defined, it is also used by print()
# When both are defined, print() uses __str__
Q4. Write a BankAccount class with deposit, withdraw, and balance check methods.
class BankAccount:
bank_name = "Indian Bank" # Class variable
def __init__(self, holder, balance=0):
self.holder = holder
self.balance = balance
def deposit(self, amount):
if amount > 0:
self.balance += amount
print(f"Deposited ₹{amount}. Balance: ₹{self.balance}")
else:
print("Deposit amount must be positive")
def withdraw(self, amount):
if amount > self.balance:
print("Insufficient balance!")
elif amount <= 0:
print("Withdrawal amount must be positive")
else:
self.balance -= amount
print(f"Withdrew ₹{amount}. Balance: ₹{self.balance}")
def check_balance(self):
print(f"Account Holder: {self.holder}")
print(f"Bank: {self.bank_name}")
print(f"Balance: ₹{self.balance}")
def __str__(self):
return f"BankAccount({self.holder}, Balance: ₹{self.balance})"
# Using the class
acc = BankAccount("Arun", 5000)
acc.deposit(3000) # Deposited ₹3000. Balance: ₹8000
acc.withdraw(2000) # Withdrew ₹2000. Balance: ₹6000
acc.withdraw(10000) # Insufficient balance!
acc.check_balance()
Q5. Demonstrate method overriding and the use of super().
class Shape:
def __init__(self, name):
self.name = name
def area(self):
return 0
def __str__(self):
return f"{self.name}: area = {self.area()}"
class Rectangle(Shape):
def __init__(self, length, breadth):
super().__init__("Rectangle") # Call parent __init__
self.length = length
self.breadth = breadth
def area(self): # Override parent method
return self.length * self.breadth
class Circle(Shape):
def __init__(self, radius):
super().__init__("Circle")
self.radius = radius
def area(self): # Override parent method
return 3.14159 * self.radius ** 2
r = Rectangle(5, 3)
c = Circle(4)
print(r) # Rectangle: area = 15
print(c) # Circle: area = 50.26544
Q6. Write a program demonstrating class methods and static methods.
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
@classmethod
def from_fahrenheit(cls, fahrenheit):
"""Class method: create object from Fahrenheit."""
celsius = (fahrenheit - 32) * 5 / 9
return cls(celsius) # calls __init__
@staticmethod
def is_freezing(celsius):
"""Static method: check if temperature is freezing."""
return celsius <= 0
def display(self):
print(f"Temperature: {self.celsius:.2f}°C")
# Using instance method
t1 = Temperature(25)
t1.display() # Temperature: 25.00°C
# Using class method as alternative constructor
t2 = Temperature.from_fahrenheit(98.6)
t2.display() # Temperature: 37.00°C
# Using static method
print(Temperature.is_freezing(-5)) # True
print(Temperature.is_freezing(20)) # False
Common Mistakes
| Mistake | Why It's Wrong | Correction |
|---|---|---|
Forgetting self in method definition | def display(): causes TypeError | Always use def display(self): |
Using __init__ as __int__ | Typo — method never called | Spell it as __init__ with double underscores |
Accessing class variable as self.class_var = value | Creates an instance variable shadowing the class variable | Use ClassName.class_var = value to change the class variable |
Not calling super().__init__() in child class | Parent attributes are not initialized | Call super().__init__(args) in child's __init__ |
Using __str__ but not __repr__ | repr() falls back to default | Define both for complete string representation |
| Confusing class method and static method | Class method takes cls, static takes neither | @classmethod uses cls; @staticmethod has no special first param |
Creating a single-element tuple (5) instead of (5,) | Parentheses make it an integer, not tuple | Always use trailing comma for single-element tuples |
Exam Checklist
- [ ] I can define a class with
__init__, instance variables, and methods - [ ] I understand the role of
selfand can use it correctly - [ ] I can differentiate between instance variables and class variables
- [ ] I can write instance methods, class methods (
@classmethod), and static methods (@staticmethod) - [ ] I can implement inheritance using
class Child(Parent): - [ ] I can use
super()to call parent class methods - [ ] I can override methods in child classes
- [ ] I can implement
__str__and__repr__for custom string representation - [ ] I can create and use objects with proper attribute access
- [ ] I can trace through OOP code and predict outputs
