Skip to content

Python · Object-Oriented Programming

Python Methods and Properties Explained — staticmethod, classmethod, and @property

3 min read Updated 2026-06-19 Share:

Practice Methods & Properties interview questions

Python methods and properties, explained

Python has three kinds of methods and a clean way to turn methods into attribute-like access. Knowing when to use @classmethod, @staticmethod, and @property — and why Python prefers properties over Java-style getters — is a common interview signal.

Three kinds of methods

The difference is what (if anything) gets passed as the first argument:

class Pizza:
    DEFAULT_SIZE = "medium"

    def __init__(self, toppings):
        self.toppings = toppings

    def describe(self):                  # instance method — gets self
        return f"Pizza with {self.toppings}"

    @classmethod
    def margherita(cls):                 # classmethod — gets the class
        return cls(["tomato", "mozzarella"])

    @staticmethod
    def is_valid_size(size):             # staticmethod — gets nothing special
        return size in {"small", "medium", "large"}
  • An instance method receives self and works with object state.
  • A classmethod receives cls (the class) and works with the class itself.
  • A staticmethod receives neither — it's a plain function namespaced under the class.

classmethod as an alternative constructor

The most common use of @classmethod is a named alternative constructor. Because it receives cls, it works correctly with subclasses too:

class Date:
    def __init__(self, year, month, day):
        self.year, self.month, self.day = year, month, day

    @classmethod
    def from_string(cls, s):
        y, m, d = map(int, s.split("-"))
        return cls(y, m, d)          # cls, not Date — subclass-friendly

Date.from_string("2026-06-19")

Using cls(...) rather than Date(...) means a subclass's from_string returns the subclass, not the base.

@property — methods that look like attributes

@property turns a method into a computed, read-only attribute accessed without parentheses:

class Circle:
    def __init__(self, radius):
        self.radius = radius

    @property
    def area(self):
        return 3.14159 * self.radius ** 2

c = Circle(2)
c.area        # 12.566...  — no parentheses; computed on access
c.area = 10   # AttributeError — read-only by default

area is always derived from radius, so it can never go stale.

Adding a setter with validation

A property can have a setter, letting you run validation while keeping plain attribute syntax:

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("below absolute zero")
        self._celsius = value

t = Temperature(20)
t.celsius = 25       # runs the setter (validates)
t.celsius = -300     # ValueError

Why properties beat Java-style getters

In Java you write getX()/setX() from the start "in case" you need validation later. In Python you just expose a plain attribute and upgrade it to a property later without changing the public API:

# Start simple:
class User:
    def __init__(self, name):
        self.name = name          # public attribute

# Later, add validation transparently — callers still write user.name:
class User:
    def __init__(self, name):
        self.name = name
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self, value):
        if not value:
            raise ValueError("name required")
        self._name = value

Callers never need to change from user.name to user.getName() — that's the payoff.

Recap

Instance methods take self and use object state; classmethods take cls and are ideal for alternative constructors that stay subclass-friendly via cls(...); staticmethods take nothing special and just live in the class namespace. @property exposes computed or read-only attributes with plain obj.attr syntax, and a paired @x.setter adds validation. Because of properties, Python code starts with public attributes and adds getters/setters later without breaking callers — so you never write Java-style boilerplate up front.

More ways to practice

The self-quiz is live. Get notified when mock interviews and new question packs drop.

or
Join our WhatsApp Channel