Practice Questions — Object-Oriented Programming in Python
← Back to NotesTopic-Specific Questions
Question 1
Easy
What is the output of the following code?
class Dog:
def __init__(self, name):
self.name = name
d = Dog("Rex")
print(d.name)The __init__ method sets self.name to the given argument.
RexQuestion 2
Easy
What is the output?
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
c1 = Cat("Whiskers", 3)
c2 = Cat("Luna", 5)
print(c1.name, c2.age)Each object has its own name and age.
Whiskers 5Question 3
Easy
What is the output?
class Greeter:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, {self.name}!"
g = Greeter("Aarav")
print(g.greet())The greet method uses self.name to build the greeting.
Hello, Aarav!Question 4
Easy
What is the output?
class Car:
wheels = 4
def __init__(self, brand):
self.brand = brand
c1 = Car("Toyota")
c2 = Car("Honda")
print(c1.wheels)
print(c2.wheels)
print(Car.wheels)wheels is a class variable shared by all instances.
444Question 5
Easy
What is the output?
class Box:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
b = Box(5, 3)
print(b.area())
print(type(b))area() returns length * width. type() gives the class.
15<class '__main__.Box'>Question 6
Medium
What is the output?
class Counter:
count = 0
def __init__(self):
Counter.count += 1
def get_count(self):
return Counter.count
a = Counter()
b = Counter()
c = Counter()
print(a.get_count())
print(Counter.count)Each __init__ call increments the class variable Counter.count.
33Question 7
Medium
What is the output?
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
return f"{self.name}: Rs.{self.price}"
def __repr__(self):
return f"Item('{self.name}', {self.price})"
i = Item("Book", 250)
print(i)
print(repr(i))print() uses __str__. repr() uses __repr__.
Book: Rs.250Item('Book', 250)Question 8
Medium
What is the output?
class MyClass:
x = 10
a = MyClass()
b = MyClass()
a.x = 20
print(a.x)
print(b.x)
print(MyClass.x)Assigning to a.x creates an instance variable on a, not modifying the class variable.
201010Question 9
Medium
What is the output?
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
return self
def pop(self):
return self.items.pop()
def size(self):
return len(self.items)
s = Stack()
s.push(1).push(2).push(3)
print(s.size())
print(s.pop())
print(s.size())push() returns self, enabling method chaining.
332Question 10
Medium
What is the output?
class Person:
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
p = Person("Priya")
print(p.get_name())
try:
print(p.__name)
except AttributeError:
print("Cannot access")Double underscore triggers name mangling.
PriyaCannot accessQuestion 11
Medium
What is the output?
class Circle:
pi = 3.14159
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return Circle.pi * self.radius ** 2
c = Circle(5)
print(round(c.area, 2))
c.radius = 10
print(round(c.area, 2))@property makes area behave like an attribute, but it is computed each time.
78.54314.16Question 12
Hard
What is the output?
class A:
data = []
def add(self, item):
self.data.append(item)
a1 = A()
a2 = A()
a1.add(1)
a2.add(2)
print(a1.data)
print(a2.data)
print(a1.data is a2.data)data is a mutable class variable. All instances share the same list.
[1, 2][1, 2]TrueQuestion 13
Hard
What is the output?
class Tracker:
def __init__(self):
self.history = []
def record(self, value):
self.history.append(value)
return self
t1 = Tracker()
t2 = Tracker()
t1.record("a").record("b")
t2.record("x")
print(t1.history)
print(t2.history)
print(t1.history is t2.history)history is created in __init__ as an instance variable. Each tracker has its own list.
['a', 'b']['x']FalseQuestion 14
Hard
What is the output?
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __str__(self):
return f"({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(1, 2)
p3 = Point(3, 4)
print(p1 == p2)
print(p1 == p3)
print(p1 is p2)
points = [p1, p2, p3]
print(p2 in points)__eq__ compares values. 'is' compares identity. 'in' uses __eq__.
TrueFalseFalseTrueQuestion 15
Hard
What is the output?
class Config:
_instance = None
def __init__(self, value):
self.value = value
@classmethod
def get_instance(cls, value):
if cls._instance is None:
cls._instance = cls(value)
return cls._instance
c1 = Config.get_instance("first")
c2 = Config.get_instance("second")
print(c1.value)
print(c2.value)
print(c1 is c2)The class method creates the instance only once (singleton pattern).
firstfirstTrueQuestion 16
Hard
What is the output?
class Number:
def __init__(self, value):
self._value = value
@property
def value(self):
print("Getting value")
return self._value
@value.setter
def value(self, new_value):
print("Setting value")
self._value = new_value
n = Number(10)
print(n.value)
n.value = 20
print(n.value)The property getter and setter print messages when accessed.
Getting value10Setting valueGetting value20Question 17
Medium
What is the difference between a class variable and an instance variable?
Think about where they are defined and who shares them.
A class variable is defined in the class body (outside any method) and is shared by all instances. A instance variable is defined using
self.variable (usually in __init__) and belongs to one specific object. Changing a class variable through the class name affects all instances. Assigning through an instance creates a new instance variable that shadows the class variable.Question 18
Hard
Why does assigning
self.count += 1 (where count is a class variable) create an instance variable instead of modifying the class variable?Expand self.count += 1 into its equivalent form.
self.count += 1 is equivalent to self.count = self.count + 1. On the right side, self.count reads the class variable (since no instance variable exists yet). Adding 1 produces a new value. On the left side, self.count = ... is an assignment through an instance, which creates a new instance variable. The class variable is never modified.Mixed & Application Questions
Question 1
Easy
What is the output?
class Rectangle:
def __init__(self, w, h):
self.w = w
self.h = h
def area(self):
return self.w * self.h
def perimeter(self):
return 2 * (self.w + self.h)
r = Rectangle(4, 6)
print(r.area())
print(r.perimeter())Area = width * height. Perimeter = 2 * (width + height).
2420Question 2
Easy
What is the output?
class Pair:
def __init__(self, a, b):
self.a = a
self.b = b
def sum(self):
return self.a + self.b
p = Pair("Hello", " World")
print(p.sum())
print(Pair(3, 7).sum())The + operator works for both strings and numbers.
Hello World10Question 3
Medium
What is the output?
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def average(self):
return sum(self.marks) / len(self.marks)
students = [
Student("Aarav", [90, 85, 92]),
Student("Priya", [88, 95, 82]),
Student("Rohan", [75, 80, 70]),
]
for s in students:
print(f"{s.name}: {s.average():.1f}")Calculate the average for each student's marks.
Aarav: 89.0Priya: 88.3Rohan: 75.0Question 4
Medium
What is the output?
class Multiplier:
def __init__(self, factor):
self.factor = factor
def multiply(self, value):
return self.factor * value
double = Multiplier(2)
triple = Multiplier(3)
results = [double.multiply(x) for x in range(1, 5)]
print(results)
print(triple.multiply(10))double.factor = 2, triple.factor = 3.
[2, 4, 6, 8]30Question 5
Medium
What is the output?
class Account:
def __init__(self, balance=0):
self.balance = balance
self.transactions = []
def deposit(self, amount):
self.balance += amount
self.transactions.append(f"+{amount}")
def withdraw(self, amount):
self.balance -= amount
self.transactions.append(f"-{amount}")
a = Account(100)
a.deposit(50)
a.withdraw(30)
a.deposit(20)
print(a.balance)
print(a.transactions)Track the balance: 100 + 50 - 30 + 20.
140['+50', '-30', '+20']Question 6
Hard
What is the output?
class Node:
def __init__(self, value, next_node=None):
self.value = value
self.next = next_node
def __str__(self):
result = str(self.value)
current = self.next
while current:
result += f" -> {current.value}"
current = current.next
return result
c = Node(3)
b = Node(2, c)
a = Node(1, b)
print(a)
print(b)Each node points to the next. __str__ follows the chain.
1 -> 2 -> 32 -> 3Question 7
Hard
What is the output?
class Matrix:
def __init__(self, rows):
self.rows = rows
def __eq__(self, other):
return self.rows == other.rows
def transpose(self):
t = list(zip(*self.rows))
return Matrix([list(row) for row in t])
m1 = Matrix([[1, 2], [3, 4]])
m2 = m1.transpose()
print(m2.rows)
print(m1 == m1.transpose().transpose())Transposing swaps rows and columns. Transposing twice gives the original.
[[1, 3], [2, 4]]TrueQuestion 8
Hard
What is the output?
class Logger:
_messages = []
@classmethod
def log(cls, message):
cls._messages.append(message)
@classmethod
def get_logs(cls):
return cls._messages.copy()
Logger.log("start")
Logger.log("process")
l1 = Logger()
l2 = Logger()
l1.log("end")
print(Logger.get_logs())
print(len(l2.get_logs()))All log calls modify the same class-level list.
['start', 'process', 'end']3Question 9
Hard
What is the output?
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
@staticmethod
def from_fahrenheit(f):
return Temperature((f - 32) * 5/9)
t1 = Temperature(100)
print(t1.fahrenheit)
t2 = Temperature.from_fahrenheit(32)
print(t2._celsius)
print(t2.fahrenheit)100C = 212F. 32F = 0C.
212.00.032.0Question 10
Medium
What is the difference between
@classmethod and @staticmethod?What does each method receive as its first parameter?
@classmethod receives the class (cls) as its first parameter and can access/modify class state. @staticmethod receives neither self nor cls and is essentially a regular function scoped inside the class. Use classmethod for alternative constructors or operations on class data. Use staticmethod for utility functions logically grouped with the class.Question 11
Hard
What is name mangling in Python? Why does Python use it instead of truly private attributes?
Double underscore attributes get renamed. Think about Python's philosophy.
Name mangling transforms
self.__attr to self._ClassName__attr. It is not true privacy -- the attribute is still accessible if you know the mangled name. Python uses this approach because of its philosophy: 'We are all consenting adults here.' Python trusts developers to follow conventions rather than enforcing strict access control. The mangling prevents accidental name collisions in subclasses, which is its primary purpose.Multiple Choice Questions
MCQ 1
What keyword is used to define a class in Python?
Answer: B
B is correct. The
B is correct. The
class keyword defines a class. Option A is not a Python keyword. Options C and D are not used for class definitions.MCQ 2
What is __init__() in a Python class?
Answer: B
B is correct.
B is correct.
__init__ is the constructor/initializer. It runs automatically when an object is created and sets up its initial state.MCQ 3
What does 'self' refer to in a class method?
Answer: B
B is correct.
B is correct.
self refers to the specific instance that the method is being called on. When obj.method() is called, self is obj.MCQ 4
What is an instance of a class called?
Answer: B
B is correct. An instance of a class is called an object. A class is the blueprint; an object is a specific entity created from that blueprint.
B is correct. An instance of a class is called an object. A class is the blueprint; an object is a specific entity created from that blueprint.
MCQ 5
How do you create an object from a class named Dog?
Answer: C
C is correct. In Python, you create objects by calling the class name as if it were a function:
C is correct. In Python, you create objects by calling the class name as if it were a function:
Dog(). This is unlike Java/C++ which use the new keyword.MCQ 6
What is the difference between self.name and name inside __init__(self, name)?
Answer: B
B is correct.
B is correct.
name is a parameter (local variable) that disappears when __init__ finishes. self.name is an instance variable that persists as an attribute of the object.MCQ 7
What happens when you assign to a class variable through an instance?
Answer: B
B is correct. Assigning through an instance (
B is correct. Assigning through an instance (
obj.x = 5) always creates or modifies an instance variable, never a class variable. The class variable remains unchanged, but the new instance variable shadows it for that specific object.MCQ 8
What does __str__() do?
Answer: B
B is correct.
B is correct.
__str__ defines the string representation used by print() and str(). Without it, printing an object shows something like <__main__.MyClass object at 0x...>.MCQ 9
What is the naming convention for Python class names?
Answer: C
C is correct. Python class names use PascalCase (also called CamelCase with initial capital):
C is correct. Python class names use PascalCase (also called CamelCase with initial capital):
Student, BankAccount, FileHandler. Methods and variables use snake_case.MCQ 10
What does @property do?
Answer: B
B is correct.
B is correct.
@property turns a method into something that can be accessed like an attribute (without parentheses). It allows you to add getter/setter logic while keeping the clean obj.attr syntax.MCQ 11
What is the purpose of __repr__() vs __str__()?
Answer: B
B is correct.
B is correct.
__str__ provides a human-friendly string (used by print). __repr__ provides an unambiguous developer-friendly string (used in the console, repr(), and when objects are in containers like lists).MCQ 12
What does Python's name mangling do with self.__attr?
Answer: B
B is correct. Python renames
B is correct. Python renames
__attr to _ClassName__attr. It is not true privacy -- the attribute can still be accessed with the mangled name. The primary purpose is preventing accidental name collisions in inheritance.MCQ 13
What is the first parameter of a @classmethod?
Answer: B
B is correct. A
B is correct. A
@classmethod receives the class itself as the first parameter, conventionally named cls. This allows it to create instances (cls(args)) and access class variables.MCQ 14
If only __repr__ is defined (no __str__), what does print(obj) use?
Answer: C
C is correct. If
C is correct. If
__str__ is not defined, Python falls back to __repr__ for print() and str(). If neither is defined, it uses the default representation showing the class name and memory address.MCQ 15
What is the purpose of __eq__(self, other)?
Answer: B
B is correct.
B is correct.
__eq__ defines the behavior of the == operator. Without it, == checks identity (same object in memory), not value equality.MCQ 16
Is 'self' a keyword in Python?
Answer: B
B is correct.
B is correct.
self is not a keyword -- it is a strong convention. You could technically use this or me, but doing so would confuse every Python developer who reads your code.MCQ 17
What happens if you define a class variable as a list and append to it through an instance?
Answer: B
B is correct.
B is correct.
self.data.append(x) does not create a new instance variable because it is not an assignment. It modifies the existing list object in place. Since the list is a class variable, the modification is visible to all instances.MCQ 18
What is returned by type(obj) if obj is an instance of class Student?
Answer: B
B is correct.
B is correct.
type(obj) returns the class of the object, which displays as <class '__main__.Student'> (or <class 'Student'> in simplified form).MCQ 19
Can a class have multiple __init__ methods (method overloading)?
Answer: B
B is correct. Python does not support method overloading. If you define __init__ twice, the second definition replaces the first. Use default parameters, *args, or @classmethod alternative constructors instead.
B is correct. Python does not support method overloading. If you define __init__ twice, the second definition replaces the first. Use default parameters, *args, or @classmethod alternative constructors instead.
MCQ 20
What does returning NotImplemented from __eq__ do?
Answer: C
C is correct. Returning
C is correct. Returning
NotImplemented (not raising NotImplementedError) is a signal to Python that this comparison is not supported. Python will then try the other operand's __eq__ method. If that also returns NotImplemented, the comparison falls back to identity comparison.Coding Challenges
Challenge 1: Student Gradebook
EasyCreate a Student class with name and marks (list). Add methods: add_mark(mark), average(), highest(), lowest(), and __str__. Test with two students.
Sample Input
(No input required)
Sample Output
Aarav - Avg: 88.7, Highest: 95, Lowest: 82
Priya - Avg: 91.0, Highest: 97, Lowest: 85
Use instance variables for name and marks. marks should be a list.
class Student:
def __init__(self, name, marks=None):
self.name = name
self.marks = marks if marks else []
def add_mark(self, mark):
self.marks.append(mark)
def average(self):
return sum(self.marks) / len(self.marks) if self.marks else 0
def highest(self):
return max(self.marks) if self.marks else 0
def lowest(self):
return min(self.marks) if self.marks else 0
def __str__(self):
return f"{self.name} - Avg: {self.average():.1f}, Highest: {self.highest()}, Lowest: {self.lowest()}"
s1 = Student("Aarav", [88, 92, 82, 95, 86])
s2 = Student("Priya", [91, 97, 85, 88, 94])
print(s1)
print(s2)Challenge 2: Bank Account with Transaction History
EasyCreate a BankAccount class with owner, balance, and a transactions list. Implement deposit(amount), withdraw(amount) with validation, and show_history(). The class variable should track total accounts created.
Sample Input
(No input required)
Sample Output
Aarav's balance: 1300
Transactions: ['+500', '-200', '+1000']
Total accounts: 2
Withdraw should fail if insufficient funds. Use a class variable for account count.
class BankAccount:
total_accounts = 0
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
self.transactions = []
BankAccount.total_accounts += 1
def deposit(self, amount):
if amount > 0:
self.balance += amount
self.transactions.append(f'+{amount}')
def withdraw(self, amount):
if amount > self.balance:
print(f"Insufficient funds for {self.owner}")
return
if amount > 0:
self.balance -= amount
self.transactions.append(f'-{amount}')
def show_history(self):
return self.transactions
a1 = BankAccount("Aarav", 0)
a1.deposit(500)
a1.withdraw(200)
a1.deposit(1000)
a2 = BankAccount("Priya", 500)
print(f"{a1.owner}'s balance: {a1.balance}")
print(f"Transactions: {a1.show_history()}")
print(f"Total accounts: {BankAccount.total_accounts}")Challenge 3: Todo List Manager
EasyCreate a TodoList class with methods: add(task), complete(index), remove(index), pending() (returns incomplete tasks), and __str__. Each task should track its completion status.
Sample Input
(No input required)
Sample Output
[x] Buy groceries
[ ] Study Python
[ ] Exercise
Pending: 2 tasks
Store tasks as a list of dictionaries with 'task' and 'done' keys.
class TodoList:
def __init__(self):
self.tasks = []
def add(self, task):
self.tasks.append({'task': task, 'done': False})
def complete(self, index):
if 0 <= index < len(self.tasks):
self.tasks[index]['done'] = True
def remove(self, index):
if 0 <= index < len(self.tasks):
self.tasks.pop(index)
def pending(self):
return [t for t in self.tasks if not t['done']]
def __str__(self):
lines = []
for t in self.tasks:
status = 'x' if t['done'] else ' '
lines.append(f"[{status}] {t['task']}")
return '\n'.join(lines)
todo = TodoList()
todo.add("Buy groceries")
todo.add("Study Python")
todo.add("Exercise")
todo.complete(0)
print(todo)
print(f"Pending: {len(todo.pending())} tasks")Challenge 4: Fraction Class with Arithmetic
MediumCreate a Fraction class that stores numerator and denominator. Implement add(other) and multiply(other) methods that return new Fraction objects. Include a simplify() method using GCD, __str__, and __eq__.
Sample Input
(No input required)
Sample Output
1/2 + 1/3 = 5/6
2/3 * 3/4 = 1/2
2/4 == 1/2: True
Always simplify fractions. Handle negative fractions. Do not use the fractions module.
def gcd(a, b):
while b:
a, b = b, a % b
return a
class Fraction:
def __init__(self, num, den):
if den == 0:
raise ValueError("Denominator cannot be zero")
if den < 0:
num, den = -num, -den
common = gcd(abs(num), abs(den))
self.num = num // common
self.den = den // common
def add(self, other):
new_num = self.num * other.den + other.num * self.den
new_den = self.den * other.den
return Fraction(new_num, new_den)
def multiply(self, other):
return Fraction(self.num * other.num, self.den * other.den)
def __eq__(self, other):
return self.num == other.num and self.den == other.den
def __str__(self):
return f"{self.num}/{self.den}"
a = Fraction(1, 2)
b = Fraction(1, 3)
print(f"{a} + {b} = {a.add(b)}")
c = Fraction(2, 3)
d = Fraction(3, 4)
print(f"{c} * {d} = {c.multiply(d)}")
print(f"2/4 == 1/2: {Fraction(2, 4) == Fraction(1, 2)}")Challenge 5: Inventory Management System
MediumCreate a Product class (name, price, quantity) and an Inventory class that manages a list of products. Inventory should have: add_product(product), remove_product(name), find_product(name), total_value() (sum of price*quantity), and low_stock(threshold) that returns products below the threshold.
Sample Input
(No input required)
Sample Output
Total value: Rs.18750
Low stock (< 10): ['Mouse']
Found: Keyboard - Rs.500 x 15
Use two classes. Product should have __str__. Inventory should manage a list.
class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
def __str__(self):
return f"{self.name} - Rs.{self.price} x {self.quantity}"
class Inventory:
def __init__(self):
self.products = []
def add_product(self, product):
self.products.append(product)
def remove_product(self, name):
self.products = [p for p in self.products if p.name != name]
def find_product(self, name):
for p in self.products:
if p.name == name:
return p
return None
def total_value(self):
return sum(p.price * p.quantity for p in self.products)
def low_stock(self, threshold=10):
return [p.name for p in self.products if p.quantity < threshold]
inv = Inventory()
inv.add_product(Product("Keyboard", 500, 15))
inv.add_product(Product("Mouse", 250, 5))
inv.add_product(Product("Monitor", 8000, 1))
print(f"Total value: Rs.{inv.total_value()}")
print(f"Low stock (< 10): {inv.low_stock(10)}")
print(f"Found: {inv.find_product('Keyboard')}")Challenge 6: Playlist Manager
MediumCreate a Song class (title, artist, duration_seconds) and a Playlist class. Playlist methods: add(song), remove(title), total_duration() (formatted as MM:SS), shuffle() (return shuffled copy), and __str__ (numbered list of songs).
Sample Input
(No input required)
Sample Output
1. Shape of You - Ed Sheeran (3:53)
2. Believer - Imagine Dragons (3:24)
3. Blinding Lights - The Weeknd (3:20)
Total duration: 10:37
Song duration stored in seconds. Display as M:SS.
class Song:
def __init__(self, title, artist, duration_seconds):
self.title = title
self.artist = artist
self.duration = duration_seconds
def formatted_duration(self):
minutes = self.duration // 60
seconds = self.duration % 60
return f"{minutes}:{seconds:02d}"
def __str__(self):
return f"{self.title} - {self.artist} ({self.formatted_duration()})"
class Playlist:
def __init__(self, name):
self.name = name
self.songs = []
def add(self, song):
self.songs.append(song)
def remove(self, title):
self.songs = [s for s in self.songs if s.title != title]
def total_duration(self):
total = sum(s.duration for s in self.songs)
minutes = total // 60
seconds = total % 60
return f"{minutes}:{seconds:02d}"
def __str__(self):
lines = [f"{i+1}. {song}" for i, song in enumerate(self.songs)]
return '\n'.join(lines)
pl = Playlist("Favorites")
pl.add(Song("Shape of You", "Ed Sheeran", 233))
pl.add(Song("Believer", "Imagine Dragons", 204))
pl.add(Song("Blinding Lights", "The Weeknd", 200))
print(pl)
print(f"Total duration: {pl.total_duration()}")Challenge 7: Vector Class with Operator Methods
HardCreate a Vector2D class with x and y. Implement __add__ (vector addition), __sub__ (vector subtraction), __mul__ (scalar multiplication), __eq__ (equality), __abs__ (magnitude), and __str__. Test thoroughly.
Sample Input
(No input required)
Sample Output
v1 + v2 = (4, 6)
v1 - v2 = (-2, -2)
v1 * 3 = (3, 6)
|v2| = 5.0
v1 == Vector2D(1, 2): True
Return new Vector2D objects from operations (do not modify originals).
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector2D(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Vector2D(self.x * scalar, self.y * scalar)
def __abs__(self):
return (self.x**2 + self.y**2) ** 0.5
def __eq__(self, other):
if not isinstance(other, Vector2D):
return NotImplemented
return self.x == other.x and self.y == other.y
def __str__(self):
return f"({self.x}, {self.y})"
def __repr__(self):
return f"Vector2D({self.x}, {self.y})"
v1 = Vector2D(1, 2)
v2 = Vector2D(3, 4)
print(f"v1 + v2 = {v1 + v2}")
print(f"v1 - v2 = {v1 - v2}")
print(f"v1 * 3 = {v1 * 3}")
print(f"|v2| = {abs(v2)}")
print(f"v1 == Vector2D(1, 2): {v1 == Vector2D(1, 2)}")Challenge 8: Linked List Implementation
HardImplement a singly linked list using Node and LinkedList classes. LinkedList should support: append(value), prepend(value), delete(value), search(value) -> bool, length(), and __str__ (display as 'a -> b -> c -> None').
Sample Input
(No input required)
Sample Output
1 -> 2 -> 3 -> 4 -> None
Length: 4
Search 3: True
After delete 2: 1 -> 3 -> 4 -> None
Do not use Python lists. Build the data structure from scratch using Node objects.
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, value):
new_node = Node(value)
if not self.head:
self.head = new_node
return
current = self.head
while current.next:
current = current.next
current.next = new_node
def prepend(self, value):
new_node = Node(value)
new_node.next = self.head
self.head = new_node
def delete(self, value):
if not self.head:
return
if self.head.value == value:
self.head = self.head.next
return
current = self.head
while current.next:
if current.next.value == value:
current.next = current.next.next
return
current = current.next
def search(self, value):
current = self.head
while current:
if current.value == value:
return True
current = current.next
return False
def length(self):
count = 0
current = self.head
while current:
count += 1
current = current.next
return count
def __str__(self):
parts = []
current = self.head
while current:
parts.append(str(current.value))
current = current.next
parts.append("None")
return " -> ".join(parts)
ll = LinkedList()
for v in [1, 2, 3, 4]:
ll.append(v)
print(ll)
print(f"Length: {ll.length()}")
print(f"Search 3: {ll.search(3)}")
ll.delete(2)
print(f"After delete 2: {ll}")Challenge 9: Class Registry with @classmethod
HardCreate a Shape class with a class-level registry. Each shape subclass (Circle, Rectangle) registers itself. Implement a from_dict(data) classmethod that creates the right shape based on a 'type' key. Include area() and __str__ for each shape.
Sample Input
(No input required)
Sample Output
Circle(radius=5) area: 78.54
Rectangle(4x6) area: 24
Registered shapes: ['circle', 'rectangle']
Use a class variable dictionary for the registry. Use @classmethod for the factory.
class Shape:
_registry = {}
@classmethod
def register(cls, shape_type, shape_class):
cls._registry[shape_type] = shape_class
@classmethod
def from_dict(cls, data):
shape_type = data.get('type')
shape_class = cls._registry.get(shape_type)
if not shape_class:
raise ValueError(f"Unknown shape: {shape_type}")
return shape_class(**{k: v for k, v in data.items() if k != 'type'})
@classmethod
def registered_shapes(cls):
return list(cls._registry.keys())
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return round(3.14159 * self.radius ** 2, 2)
def __str__(self):
return f"Circle(radius={self.radius})"
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def __str__(self):
return f"Rectangle({self.width}x{self.height})"
Shape.register('circle', Circle)
Shape.register('rectangle', Rectangle)
c = Shape.from_dict({'type': 'circle', 'radius': 5})
r = Shape.from_dict({'type': 'rectangle', 'width': 4, 'height': 6})
print(f"{c} area: {c.area()}")
print(f"{r} area: {r.area()}")
print(f"Registered shapes: {Shape.registered_shapes()}")Need to Review the Concepts?
Go back to the detailed notes for this chapter.
Read Chapter NotesWant to learn Python with a live mentor?
Explore our Python course