On this page
01Why interviewers ask this
Every coding round starts the same way. You open an empty editor and must decide what to type first. In most problems the answer is: a class. A class is a named piece of code that keeps some data together with the actions that use that data.
A weak answer keeps the data in loose values and writes many separate pieces of code that take those values as input. It works for the first version. When a rule changes, you search the whole file for every place that touches the data. A strong answer gives each thing in the problem its own small class. The data and the actions on it sit in one place, so a change has one place to go.
At SDE-1 level you should write a small class without help and run it. At SDE-2 level you should also say which class owns which data and why. The scoring of the round (lesson 7) gives 25 points to object design, so this is the base of everything that follows.
02The idea in plain words
Think of a prepaid card for a college canteen. You load money on the card, and you tap it at the counter to pay. The card itself knows whose it is and how much is left. Loading money and paying are things you do with the card. Now think of the other way: a notebook at the counter with all names and balances, and a separate sheet of rules. The cashier must find the right line and apply the right rule. A wrong line is easy to pick.
This lesson assumes you know if, for loops, print and +=. The new ideas are class and object.
Code can be written in both ways. Here is the notebook way for two cards. A dictionary is a collection of named values: here "holder" and "balance". A function is a named block of code that takes inputs.
card_a = {"holder": "Asha", "balance": 100}
card_b = {"holder": "Ravi", "balance": 40}
def pay(card, amount):
card["balance"] -= amount
pay(card_a, 30)
print(card_a["balance"], card_b["balance"])This prints 70 40. It works, but nothing connects the function to the data. You can call pay with any dictionary, including one that is not a card. A typo such as "balence" fails only when that line runs. Nobody knows which functions work on a card, unless they read the whole file.
Class, object, field, method
A class is a blueprint: it says what a thing keeps and what it can do. An object is one thing made from the blueprint. One class, CanteenCard, can make many objects: Asha's card, Ravi's card. A field is a named piece of data that an object keeps, such as its balance. A method is an action that the object can do. It is a function that lives inside the class.
class CanteenCard:
def __init__(self, card_id, holder, balance):
self.card_id = card_id
self.holder = holder
self.balance = balance
def top_up(self, amount):
self.balance += amount
def pay(self, amount):
self.balance -= amountRead it slowly:
class CanteenCard:starts the blueprint. The name is a noun, with a capital letter for every word.__init__is the constructor: the method that runs once, when an object is made. It sets the first value of each field.selfmeans "this object". Python passes it as the first input of every method.self.balanceis the balance of this card, and no other card.- To make an object, call the class like a function:
asha = CanteenCard("C101", "Asha", 100). You do not writeself; Python fills it in. - To use an object, write the object, a dot and the name.
asha.pay(30)runspayon Asha's card.asha.balancereads the field. - Code outside the class can also set a field with
=, for exampleasha.balance = 500. Python does not check the new value.
Each object has its own fields. asha.pay(30) changes Asha's balance and leaves Ravi's card alone. The wrong card cannot be hit, because the method belongs to the card.
State, and values that are the same for every card
The state of an object is the current value of all its fields. It changes over time. top_up and pay change the state. Other methods only look at the state and return an answer. Name them so a reader can tell: pay is a verb that changes things, and is_low is a question.
Some values are the same for every card, such as the amount below which we call a balance low. Put it in the class, outside any method, in capital letters. This is a class-level constant. A field set in __init__ is different: every object has its own copy. Add these lines inside the class, after pay:
LOW_BALANCE = 20
def is_low(self):
return self.balance < CanteenCard.LOW_BALANCEA warning: never put a value that changes, such as an empty list, at class level. All objects then share one list. The Python tutorial warns about this. If you want a list for each object, create it in __init__ with self.
Seeing an object while you debug
If you print an object, Python shows a code such as 0x7f3a that means nothing to you. The method __repr__ fixes this. It returns the text that Python shows for the object. Add it inside the class too:
def __repr__(self):
return f"CanteenCard({self.card_id}, {self.holder}, Rs {self.balance})"The text starting with f" is a text with {...} holes. Python puts the value of each hole into the text. Now print(asha) shows CanteenCard(C101, Asha, Rs 70). This helps a lot when you debug.
Same object, or equal objects
Two objects can hold the same data and still be two objects. a is b asks "is it the same object?" a == b asks "are they equal?" For a plain class like this one, == also means "the same object". So two cards with the same id, holder and balance are not equal. To compare by meaning, compare a field: a.card_id == b.card_id.
None: no value
None is the Python value for "no value here". Use x is None to ask whether x is that value. It is the right way to check for "nothing", because is asks about the same object.
Objects in lists and dictionaries
An object is a normal value. You can put objects in a list or in a dictionary. A common shape in a round is a registry. It is a dictionary that maps an id to an object, so you can find a card from its id. The loop for card in [asha, ravi]: registry[card.card_id] = card stores each card under its id. Then registry.get("C102") gives the object, or None if the id is not in the registry.
Names and size
Use a noun for a class (CanteenCard, Receipt). Use a verb for a method that does something (pay, top_up) and a question for a method that only looks (is_low). Keep a class small, with one clear job. If you cannot describe it in one sentence without the word "and", split it.
When a function is better
If a piece of code keeps no state between calls, a plain function is enough. A function that adds GST (a sales tax) to a price needs no class. Do not make a class only to hold one function.
Reading the Python
If you write Java, JavaScript or C++, the ideas are the same. Only the words change.
| Python | Java | JavaScript | C++ |
|---|---|---|---|
class CanteenCard: | class CanteenCard | class CanteenCard | class CanteenCard |
__init__ (constructor) | a method with the class name | constructor | a function with the class name |
self.balance | this.balance | this.balance | this->balance |
| list | ArrayList | array | std::vector |
| dictionary | HashMap | Map | std::unordered_map |
None | null | null | nullptr |
Want to check your understanding? Try explaining this idea in your own words. You can continue reading first, or ask the AI tutor a question. Sign up free to ask the tutor
03Pause and predict
Pause. Guess first.
Asha's card has Rs 100 and Ravi's card has Rs 40. The code runs
asha.pay(30). What are the two balances now? Then someone runsasha.balance = -500. Does Python stop this?
Write your guess before you read on. The answer is in the worked example.
04Worked example
Run with Python 3.11, with the CanteenCard class above (the first listing plus the two added pieces). Assumption: Asha's card has Rs 100, Ravi's card has Rs 40, and a balance below Rs 20 counts as low.
asha = CanteenCard("C101", "Asha", 100)
ravi = CanteenCard("C102", "Ravi", 40)
asha.pay(30)
print(asha.balance, ravi.balance)
print(asha)It prints 70 40 and then CanteenCard(C101, Asha, Rs 70). The arithmetic: 100 - 30 = 70. Ravi's card did not move: it is still 40. The two objects are independent.
Now put both in a registry and use it.
registry = {}
for card in [asha, ravi]:
registry[card.card_id] = card
print(registry["C102"].holder)
print(registry.get("C999"))
ravi.top_up(50)
print(registry["C102"].balance)
asha.pay(55)
print(asha.balance, asha.is_low())The output is Ravi, None, 90, and 15 True. Step by step: the id C102 finds Ravi's card. The id C999 has no card, so get gives None. Ravi's top-up gives 40 + 50 = 90. Asha pays 55 more: 70 - 55 = 15. Fifteen is below 20, so is_low() is True. The registry holds the same objects, not copies, so registry["C102"].balance shows the top-up.
Two last checks, on equality and on setting a field from outside.
a = CanteenCard("C1", "Asha", 100)
b = CanteenCard("C1", "Asha", 100)
print(a == b, a is b, a is a, a.card_id == b.card_id)
asha.balance = -500
print(asha.balance)It prints False False True True, and then -500. This answers the predict box. After asha.pay(30) the balances are 70 and 40. And Python does not stop asha.balance = -500. Any code can set a field from outside. A canteen card with a balance of minus Rs 500 is wrong, but the class as we wrote it allows it. This class keeps data and actions together, but it does not protect its data.
05Trade-offs
A class solves the problem of loose data. The data and its actions are in one place. Each object has its own state. The right method is easy to find. It costs more lines than a dictionary, and you must decide what each class owns. A class also does not guard its fields by itself: as the example shows, outside code can set any value. I would change to a plain function when there is no state. I would change to a plain dictionary when you only carry a few values and no rule belongs to them.
06Common misconceptions
"A class is only another name for a dictionary." A dictionary holds data and nothing else. A class also holds the actions, and each method belongs to its object. This is why asha.pay(30) cannot change Ravi's card.
"Two objects with the same data are equal." For a plain class they are not. In the example, a == b is False even though every field is the same. Compare ids or fields when you mean "the same card".
"A list written at class level belongs to each object." It belongs to the class, and all objects share it. Create a list for each object inside __init__.
07How to say it in the interview
Say it like this
I put each thing in the problem in a small class: a noun for the class, its data as fields, its actions as methods. Each object keeps its own state, so a rule has one place to live and two objects never mix.
08Check your understanding
- What does
selfmean in a method, and when does__init__run? - A new card
CanteenCard("C103", "Meera", 100)getstop_up(50), thenpay(30), thenpay(45). What is the balance? Isis_low()true? - A teammate writes
class Cart:with the lineitems = []at class level. The methodaddrunsself.items.append(x), andappendadds one item at the end of a list. Two carts are made, and one item is added to the first. What does the second cart show, and what do you change?
09Answers
Show the answers
selfmeans "this object", the one the method was called on.__init__runs once, when the object is made, and sets the first value of the fields.- 100 + 50 = 150. Then 150 - 30 = 120. Then 120 - 45 = 75. The balance is Rs 75. It is not below 20, so
is_low()isFalse. - The second cart shows the same item, because
itemsbelongs to the class and one list is shared. Move the line into__init__asself.items = [], so each cart gets its own list.
10Summary card: classes and objects
One-page summary
- Idea. A class is a blueprint. An object is one thing made from it. Data (fields) and actions (methods) live together.
- Words. Constructor
__init__runs once.selfis this object. A registry is a dictionary from id to object.Nonemeans no value.- Rules. Each object has its own fields. A class-level constant is shared by all. Never put a changing list at class level.
- Compare.
a is basks if it is the same object.==on a plain class says the same.- Names. Nouns for classes, verbs for actions, questions for methods that only look.
- Trade-off. It solves loose data. It costs more lines. It does not guard its fields.
- Trap. Setting
card.balance = -500from outside is allowed.
11Sources
- Python tutorial, "Classes", section 9.3.5 "Class and Instance Variables", which warns about shared class variables: https://docs.python.org/3/tutorial/classes.html (opens in a new tab) (checked 29 Oct 2026).
- The canteen card, the names and the amounts are made up for teaching. All code was run with Python 3.11.
Try what you just learned
Put this idea into practice with a short exercise or a relevant tool. Free to try. No sign-up needed.
More practice. This needs a free account.
What to learn next
Continue learning with the lessons that build on this one.
- Interfaces and polymorphism: one call, many behaviours
- Lists, maps and sets: pick by the question you ask
- How a machine-coding round works
Practise this idea
Have a question about this lesson?
Ask the AI tutor to explain a difficult idea, walk through an example or check your understanding. It uses the lesson to help you work through the topic.
A free account includes 10 AI tutor questions a day. The lesson remains free to read without an account.
All lessons in Module 2: Low-level design and machine coding
Prefer another topic? Browse all 169 lessons.