Methods & Properties Interview Questions & Answers
5 questions Updated 2026-06-18
Python interview questions on instance vs classmethod vs staticmethod, classmethods as alternative constructors, the @property getter/setter, why properties beat Java-style accessors, and computed/read-only properties.
An instance method takes self and operates on a specific object. A
@classmethod takes cls (the class, not an instance) and works on
class-level state or builds instances. A @staticmethod takes
neither — it's a plain function namespaced inside the class, with no access
to instance or class state.
class Pizza:
base_price = 10
def __init__(self, toppings):
self.toppings = toppings
def total(self): # instance method — uses self
return self.base_price + len(self.toppings)
@classmethod
def margherita(cls): # classmethod — uses cls
return cls(["mozzarella", "basil"])
@staticmethod
def is_valid_topping(name): # staticmethod — no self/cls
return name.isalpha()
Pizza.is_valid_topping("ham") # True — no instance needed
Pizza.margherita().total() # 12
Use an instance method for per-object behavior, a classmethod for class-aware logic (e.g. alternative constructors), and a staticmethod for a related helper that happens to live on the class.
A classmethod receives cls, so it can build and return a new instance from
a different input format — giving you multiple named constructors beyond
__init__. Using cls (not the hard-coded class name) means subclasses get
the right type automatically.
class Date:
def __init__(self, year, month, day):
self.year, self.month, self.day = year, month, day
@classmethod
def from_string(cls, text):
y, m, d = map(int, text.split("-"))
return cls(y, m, d) # returns the (sub)class instance
@classmethod
def today(cls):
import datetime
t = datetime.date.today()
return cls(t.year, t.month, t.day)
Date.from_string("2026-06-18") # alternative constructor
Date.today()
This is the idiomatic Python pattern (dict.fromkeys, datetime.fromtimestamp)
for "make one of these, but from X" — clearer than overloading __init__ with
flags.
@property turns a method into a managed attribute — you access it like
obj.x (no parentheses), but a method runs behind the scenes. The matching
@x.setter runs on assignment, letting you add validation without changing
the public interface.
class Account:
def __init__(self, balance):
self._balance = balance # "private" backing field
@property
def balance(self): # getter — runs on read
return self._balance
@balance.setter
def balance(self, value): # setter — runs on write
if value < 0:
raise ValueError("balance cannot be negative")
self._balance = value
acc = Account(100)
acc.balance # 100 — looks like an attribute, calls the getter
acc.balance = 50 # calls the setter (validated)
acc.balance = -1 # ValueError
The convention is a _name backing attribute behind a public property. Omit the
setter to make the property read-only.
In Python you start with a plain attribute and only convert it to a
@property later if you need validation or computation — without changing
the call sites. So you avoid the Java habit of pre-emptively writing
getX()/setX() "just in case". The public API stays obj.x.
# Start simple — public attribute:
class Circle:
def __init__(self, radius):
self.radius = radius
c = Circle(5)
c.radius # direct access — no ceremony
# Later, add validation transparently — callers don't change:
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value <= 0:
raise ValueError("radius must be positive")
self._radius = value
This is the "uniform access principle": callers can't tell whether obj.x is a
stored value or computed. Don't write getters/setters upfront — reach for a
property only when behavior is needed.
A property with only a getter (no setter) is read-only — assigning to it
raises AttributeError. A computed property derives its value from other
attributes on each access, so it stays in sync automatically rather than being
stored.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self): # computed — derived on each read
return self.width * self.height
r = Rectangle(3, 4)
r.area # 12 — computed
r.width = 5
r.area # 20 — automatically reflects the change
r.area = 99 # AttributeError — read-only (no setter)
For an expensive computation you only want to run once, use
functools.cached_property instead, which caches the result on first access.
Use a plain read-only property for cheap derived values.
Practice tests are coming soon
Get notified when interactive mock interviews and quizzes launch.