Classes & Objects β Python Questions with Answers
Start with the study notes on Classes & Objects (definitions, examples and a quick revision), then work through 30 practice questions, each with the correct answer and a clear explanation of why it is right. When you are ready, take this topic as an interactive quiz to test yourself.
11 easy Β· 14 medium Β· 5 hard Β· Part of Python: Master Python from basics to advanced - 20 topics.
Topic overview
Classes and Objects β your own data types
1. Class and object
A class is a blueprint; an object (or instance) is a thing built from it. A class bundles data (attributes) with the functions that work on it (methods).
Example: A Dog class is the cookie cutter; rex and buddy are two cookies, each with their own name and age.
2. Defining a class: __init__ and self
class Dog: starts the class. Class names use CamelCase.
__init__ runs automatically when you create an object, and sets up its attributes.
self is the object itself. self.name = name stores a value on the object.
Create an object by calling the class: Dog("Rex"). Python has no new keyword.
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(self.name, "says woof")
rex = Dog("Rex", 3)
buddy = Dog("Buddy", 5)
rex.bark()
print(buddy.name, buddy.age)
OutputRex says woof
Buddy 5
Remember:rex.bark() is really Dog.bark(rex): the object is passed in as self. Forget self in the def, and the call fails with βtakes 0 positional arguments but 1 was givenβ.
3. Objects keep their own state
Each object has its own attributes, and methods can change them.
class Account:
def __init__(self, balance=0):
self.balance = balance
def deposit(self, amount):
self.balance += amount
return self.balance
a = Account(100)
b = Account()
print(a.deposit(50), b.balance)
Output150 0
4. Class attributes vs instance attributes
A class attribute, written in the class body, is shared by all objects.
An instance attribute, set through self.x in __init__, belongs to each object separately.
class Dog:
count = 0 # class attribute: shared
def __init__(self, name):
self.name = name # instance attribute: per dog
Dog.count += 1
a, b, c = Dog("Rex"), Dog("Max"), Dog("Leo")
print(Dog.count, a.name, c.name)
Output3 Rex Leo
The shared list trap
A list in the class body is shared by every object. Create per-object lists in __init__.
class Team:
members = [] # ONE list for all teams!
def add(self, name):
self.members.append(name)
x, y = Team(), Team()
x.add("Ana")
print(y.members)
Output['Ana']
5. Printing and comparing objects
By default, print(obj) shows something like <__main__.Dog object at 0x...>, and == checks whether two names are the same object. Defining __str__ and __eq__ changes this (see Magic Methods).
class Dog:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Dog named {self.name}"
def __eq__(self, other):
return self.name == other.name
print(Dog("Rex"))
print(Dog("Rex") == Dog("Rex"))
OutputDog named Rex
True
6. Inspecting objects
class Dog:
def __init__(self, name):
self.name = name
rex = Dog("Rex")
rex.age = 3 # objects accept new attributes
print(rex.__dict__)
print(isinstance(rex, Dog))
print(hasattr(rex, "color"), getattr(rex, "color", "unknown"))
Remember: Reading a missing attribute raises AttributeError. Define all attributes in __init__, so a typo like rex.nmae = ... doesn't silently create a new one.
7. Why use classes?
Classes keep related data and behaviour together, so bigger programs stay organised. This idea is called encapsulation.
Example: A BankAccount keeps its balance together with deposit() and withdraw(), instead of loose variables and separate functions.
8. Common misconceptions
Misconception
Correct understanding
self is a keyword you can leave out.
self must be the first parameter of every normal method.
Changing one object's attribute changes the others.
Instance attributes belong to each object separately.
A list in the class body gives each object its own list.
It is shared by all objects; create it in __init__.
Two objects with equal data are == by default.
By default == checks identity; define __eq__ to compare data.
You need new to create an object.
Call the class like a function: Dog("Rex").
9. Quick revision
Class
A blueprint for objects.
Object / instance
A thing made from a class.
__init__
Sets up a new object's attributes.
self
The object a method is working on.
Attribute
Data stored on an object, e.g. rex.name.
Method
A function defined in a class.
Class attribute
Shared by all objects of the class.
Encapsulation
Keeping data and its methods together.
10. Test your understanding
What is the difference between a class and an object?
Show answer
The class is the blueprint; an object is a thing built from it.
When does __init__ run?
Show answer
Automatically, whenever a new object is created.
What does self refer to?
Show answer
The object the method was called on.
How do you create a Dog object?
Show answer
Dog("Rex")
What error do you get if a method is defined without self?
Show answer
TypeError: it takes 0 positional arguments but 1 was given.
What is a class attribute?
Show answer
One value shared by all objects of the class.
Why is members = [] in a class body a trap?
Show answer
All objects share the same list.
What does print(obj) show without __str__?
Show answer
Something like <__main__.Dog object at 0x...>.
Key takeaway: A class is a blueprint: __init__ sets up each object's data through self, methods act on it, and each object keeps its own state.
Notes written by Velnov. Every code example with an output was run in Python 3 to check that the output shown is exactly what Python prints.
What is the relationship between a CLASS and an OBJECT?
class Dog: # blueprint
pass
rex = Dog() # object #1
buddy = Dog() # object #2
A A class is the blueprint; objects are the individual things built from it
B They are the same thing
C Objects contain classes
D A class is one specific example of an object
Answer: A β A class is the blueprint; objects are the individual things built from it
The class defines what attributes and methods exist (the cookie cutter); each object (instance) is a concrete item made from it (a cookie) with its own data.
ClassesInstances
Q2.easy
Which is the correct syntax to define a class?
class Student:
def __init__(self, name):
self.name = name
A class Student:
B def Student:
C class Student():{}
D new class Student
Answer: A β class Student:
The class keyword, a name (CamelCase by convention), and a colon. The body - methods and attributes - is indented below.
class keywordNaming conventions
Q3.easy
What is the purpose of the __init__ method?
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
s = Student("Ravi", "A") # __init__ runs here
print(s.name) # Ravi
A To delete an object
B To initialize a new object's attributes - it runs automatically on creation
C To import the class
D To print the object
Answer: B β To initialize a new object's attributes - it runs automatically on creation
__init__ is the initializer: Python calls it automatically every time you create an instance, letting you set up the object's starting attribute values.
__init__Constructors
Q4.easy
What does self refer to inside a class method?
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(self.name, "says woof")
rex = Dog("Rex")
rex.bark() # Rex says woof (self = rex)
A The class itself
B The specific OBJECT the method was called on
C The Python interpreter
D The parent class
Answer: B β The specific OBJECT the method was called on
self is the current instance - when you call rex.bark(), self IS rex inside the method. It's how each object accesses ITS OWN attributes: self.name, self.age.
selfInstances
Q5.easy
How do you CREATE an object of class Dog?
class Dog:
def __init__(self, name):
self.name = name
d = Dog("Rex")
A d = Dog()
B d = new Dog()
C d = create Dog
D d = Dog.new()
Answer: A β d = Dog()
Call the class like a function: Dog(). Arguments go to __init__: Dog("Rex", 3). No 'new' keyword in Python (that's Java/JavaScript/C++).
Instantiation
Q6.easy
What does self.name = name do inside __init__(self, name)?
def __init__(self, name):
self.name = name # kept on the object
nickname = name # lost after __init__!
A Stores the parameter's value as an ATTRIBUTE on the object, so it survives after __init__ ends
B Creates a global variable
C Renames the class
D Nothing - it's redundant
Answer: A β Stores the parameter's value as an ATTRIBUTE on the object, so it survives after __init__ ends
The parameter name is a temporary local variable; self.name attaches the value to the OBJECT itself, making it available later as obj.name. Without self. the value would vanish when __init__ returns.
Attributesself
Q7.easy
How do you read the name attribute of object s?
s = Student("Ana")
print(s.name) # Ana
s.name = "Anita" # attributes can be updated too
A s.name
B s[name]
C name(s)
D s->name
Answer: A β s.name
Dot notation: object.attribute. (Square brackets are for lists/dicts; arrows are C++.)
Dot notationAttributes
Q11.easy
By convention, class names are written in:
A CamelCase: BankAccount, StudentRecord
B snake_case: bank_account
C ALLCAPS: BANKACCOUNT
D lowercase: bankaccount
Answer: A β CamelCase: BankAccount, StudentRecord
PEP 8: classes use CamelCase (CapWords); functions/variables use snake_case; constants use ALL_CAPS. Seeing BankAccount() you instantly know it's a class.
PEP 8Naming conventions
Q22.easy
What is the main benefit of OOP (classes) over loose variables and functions?
A It bundles related DATA and the FUNCTIONS that work on it into one unit
B Programs always run faster
C Less typing in all cases
D It's required by Python
Answer: A β It bundles related DATA and the FUNCTIONS that work on it into one unit
A BankAccount class keeps balance (data) and deposit/withdraw (behavior) together - instead of parallel lists and free functions hoping to stay in sync. Encapsulation makes bigger programs manageable.
EncapsulationOOP benefits
Q27.easy
A class Car should store its color and speed. Which __init__ is right?
Take self plus the values, then store each with self.attr = value. Option B forgets self entirely; C misspells __init__ and stores nothing; D never receives the values.
__init__Attributes
Q30.easy
In rex = Dog("Rex"), which part triggers __init__?
A Calling the class: Dog("Rex")
B The assignment to rex
C The quotes around Rex
D __init__ must be called manually
Answer: A β Calling the class: Dog("Rex")
Calling a class creates the object and automatically runs __init__ with your arguments. The assignment merely names the finished object.
Instantiation__init__
Medium questions (14)
Q8.medium
Why must methods declare self as their first parameter?
class Dog:
def bark(self): # receives the instance
print("woof")
rex.bark() # same as Dog.bark(rex)
A Python passes the instance automatically as the first argument - self receives it
B It's optional decoration
C For speed
D To make methods private
Answer: A β Python passes the instance automatically as the first argument - self receives it
rex.bark() is really Dog.bark(rex) behind the scenes - the instance is passed in as the first argument, which the method receives as self. Forget self in the def and calls break.
selfMethod calls
Q9.medium
What error results from this, and when?
class Dog:
def bark():
print("woof")
Dog().bark()
class Dog:
def bark(self): # fixed
print("woof")
A TypeError when calling - bark() takes 0 arguments but 1 was given (the instance!)
B SyntaxError at definition
C No error
D NameError
Answer: A β TypeError when calling - bark() takes 0 arguments but 1 was given (the instance!)
The def compiles fine, but the CALL passes the instance automatically - and bark() declared no parameter to receive it. The confusing message 'takes 0 positional arguments but 1 was given' almost always means: you forgot self.
Learn to recognize this error message - everyone hits it.
selfTypeError
Q10.medium
a = Dog("Rex") and b = Dog("Buddy"). Does changing a.name affect b.name?
a = Dog("Rex")
b = Dog("Buddy")
a.name = "King"
print(b.name) # Buddy - unaffected
A No - each instance has its OWN attributes
B Yes - all objects share attributes
C Only if they were created on the same line
D b is deleted
Answer: A β No - each instance has its OWN attributes
Instance attributes (set via self.x = ...) belong to each object separately. a and b are independent - that's the point of instances.
Instance attributesIndependence
Q12.medium
What is the difference between a FUNCTION and a METHOD?
A A method is a function defined inside a class and called on an object: obj.method()
B Methods are faster
C Functions can't take arguments
D No difference at all
Answer: A β A method is a function defined inside a class and called on an object: obj.method()
Methods live in classes and receive the instance (self) automatically: "hi".upper(), list.append(), dog.bark(). Plain functions stand alone: len(), print().
MethodsFunctions
Q13.medium
What is the output?
class Counter:
def __init__(self):
self.count = 0
def increment(self):
self.count += 1
c = Counter()
c.increment()
c.increment()
print(c.count)
A 0
B 1
C 2
D Error
Answer: C β 2
count starts at 0 in __init__; each increment() adds 1 to THIS object's count: 0 -> 1 -> 2. Objects carrying state between method calls is the essence of OOP.
self gives access to everything on the object - attributes AND other methods. Building bigger methods from smaller ones keeps classes tidy.
selfMethod composition
Q19.medium
What does this print?
class Product:
def __init__(self, name, price=100):
self.name = name
self.price = price
p = Product("Pen")
print(p.price)
A 100
B None
C Error - price missing
D 0
Answer: A β 100
__init__ is a normal function - default parameter values work exactly the same: price defaults to 100 when not supplied.
Default arguments__init__
Q21.medium
What does print(rex) show by DEFAULT (no __str__ defined)?
class Dog:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Dog named {self.name}"
print(Dog("Rex")) # Dog named Rex
A Something like <__main__.Dog object at 0x000001A2B3C4D5E6>
B All the attributes nicely formatted
C The name attribute
D Nothing
Answer: A β Something like <__main__.Dog object at 0x000001A2B3C4D5E6>
The default representation shows the class and memory address - not helpful. Define __str__ to control what print() shows (covered in the Magic Methods topic).
__str__Object representation
Q23.medium
Can you add a NEW attribute to an object after creation?
rex = Dog("Rex")
rex.tricks = ["sit"]
A Yes - Python objects accept new attributes at any time (by default)
B No - only __init__ can create attributes
C Only with add_attribute()
D It deletes the object
Answer: A β Yes - Python objects accept new attributes at any time (by default)
Python is dynamic - rex.tricks = [...] just works, attaching the attribute to that one object. Handy but risky (typos create NEW attributes silently: rex.nmae = ... !). Best practice: define everything in __init__.
A typo like rex.nmae = 'x' creates a new attribute instead of failing!
Dynamic attributesBest practices
Q24.medium
Trace the output:
class Account:
def __init__(self, balance):
self.balance = balance
def deposit(self, amt):
self.balance += amt
return self.balance
acc = Account(100)
print(acc.deposit(50))
A 150
B 100
C 50
D None
Answer: A β 150
balance starts at 100; deposit adds 50 and returns the new balance: 150. A miniature of every real-world class: state + methods that change it.
StateTracing
Q26.medium
Where does the code in the CLASS BODY (outside methods) run?
class Config:
print("setting up")
version = 1
A Once, when the class statement is first executed - NOT on each instance
B Every time an object is created
C Never
D On every method call
Answer: A β Once, when the class statement is first executed - NOT on each instance
The class body executes top-to-bottom ONCE to build the class - creating class attributes and methods. Creating instances later runs only __init__, not the body again.
Class bodyClass creation
Q29.medium
isinstance(x, (int, float)) returns True when...
def half(x):
if not isinstance(x, (int, float)):
raise TypeError("number required")
return x / 2
A x is an int OR a float (or a subclass of either)
B x is both at once
C x is exactly the tuple (int, float)
D Never - invalid syntax
Answer: A β x is an int OR a float (or a subclass of either)
isinstance accepts a tuple of types - True if x matches ANY of them. The standard way to accept 'any number'.
isinstance()Type checking
Hard questions (5)
Q14.hard
What is the difference between these two attributes?
class Dog:
species = "canine" # (1)
def __init__(self):
self.name = "Rex" # (2)
print(Dog.species) # canine - via the class
a, b = Dog(), Dog()
print(a.species) # canine - shared
a.name = "King" # only a's name changes
A (1) is a CLASS attribute shared by all dogs; (2) is an INSTANCE attribute unique to each dog
B Both are identical
C (1) is private, (2) is public
D (2) is shared, (1) is unique
Answer: A β (1) is a CLASS attribute shared by all dogs; (2) is an INSTANCE attribute unique to each dog
species lives on the CLASS - one copy, seen by every instance (Dog.species). self.name lives on EACH object separately. Use class attributes for values common to all instances.
Class attributesInstance attributes
Q15.hard
What is the output?
class Dog:
count = 0
def __init__(self):
Dog.count += 1
a = Dog(); b = Dog(); c = Dog()
print(Dog.count)
A 0
B 1
C 3
D Error
Answer: C β 3
Dog.count is a class attribute - one shared counter. Each __init__ increments it, so after three instances it's 3. A classic pattern for counting how many objects exist.
Class attributesCounting instances
Q20.hard
What is the output?
a = Dog("Rex")
b = Dog("Rex")
print(a == b)
class Dog:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name == other.name
print(Dog("Rex") == Dog("Rex")) # True now
A False - by default == compares object IDENTITY, and these are two separate objects
B True - same name means equal
C Error
D None
Answer: A β False - by default == compares object IDENTITY, and these are two separate objects
Unless a class defines __eq__, == falls back to 'are they the SAME object?' - and a, b are two distinct instances, however identical their data. Defining __eq__ lets you compare by content.
A A dict of the object's instance attributes: {'name': 'Rex', 'age': 3}
B The class's methods
C Python's built-in dictionary
D Nothing - it's an error
Answer: A β A dict of the object's instance attributes: {'name': 'Rex', 'age': 3}
Instance attributes are literally stored in a dict per object - __dict__ exposes it. Great for debugging: see exactly what data an object carries.
__dict__Introspection
Q28.hard
What is the output?
class Team:
members = []
def add(self, name):
self.members.append(name)
a = Team(); b = Team()
a.add("Ana")
print(b.members)
class Team:
def __init__(self):
self.members = [] # each team its own list
A ['Ana'] - the CLASS-level list is shared by ALL instances!
B [] - each team has its own list
C Error
D None
Answer: A β ['Ana'] - the CLASS-level list is shared by ALL instances!
members = [] in the class body creates ONE list on the class, shared by every instance - a.add() mutates the list b sees too. For per-instance lists, create them in __init__: self.members = [].
The mutable-class-attribute trap - sibling of the mutable default argument.