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.