Skip to content

Python · Object-Oriented Programming

Python @classmethod vs @staticmethod vs Instance Method — When to Use Each

5 min read Updated 2026-06-21 Share:

Practice classmethod vs staticmethod vs instance method interview questions

Three method types, one class

Python classes support three kinds of methods, and the distinction trips up almost every developer at some point. The difference is not about access control — it's about what the method receives as its implicit first argument, which determines what it can see and do.

Quick-reference comparison

Instance method@classmethod@staticmethod
First argumentself — the instancecls — the class itselfNothing — no implicit arg
Access to instance?YesNoNo
Access to class?Yes (via type(self) or self.__class__)Yes (via cls)No
Callable on class?No (needs an instance)YesYes
Callable on instance?YesYes (cls is still the class)Yes
Subclass safe?Yes — type(self) gives subclassYes — cls gives the subclassNo — no class reference at all
Main usePer-object behaviourAlternative constructors, class-level logicUtility helpers with no class/instance coupling

Instance methods — the default

An instance method takes self as its first argument and operates on one particular object. It has full access to instance state and can also reach the class via type(self) or self.__class__.

class BankAccount:
    interest_rate = 0.05          # class-level state

    def __init__(self, balance):
        self.balance = balance    # instance-level state

    def deposit(self, amount):    # instance method — needs self
        self.balance += amount
        return self.balance

account = BankAccount(1000)
account.deposit(200)              # self = account, amount = 200

Instance methods are the right choice for anything that operates on or mutates a specific object's state.

@classmethod — the alternative constructor pattern

A classmethod receives cls (the class, not an instance) as its first argument. It can't see instance state, but it can create instances, read or modify class-level attributes, and call other class methods. The most common use is an alternative constructor — a named factory method for building instances from a different input format.

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

    @classmethod
    def from_string(cls, text):         # alternative constructor
        year, month, day = map(int, text.split("-"))
        return cls(year, month, day)    # cls, not Date — subclass safe

    @classmethod
    def today(cls):
        import datetime
        t = datetime.date.today()
        return cls(t.year, t.month, t.day)

Date.from_string("2026-06-21")          # no instance needed
Date.today()

Why cls instead of Date? Subclasses inherit the classmethod. Using cls means a subclass gets an instance of itself — using the hard-coded class name Date breaks subclassing:

class ExtendedDate(Date):
    pass

type(ExtendedDate.from_string("2026-01-01"))   # ExtendedDate — correct with cls
# would be Date — wrong if from_string() used `Date(...)` directly

This is the same pattern as dict.fromkeys, datetime.datetime.fromtimestamp, and int.from_bytes in the standard library.

Deep dive: Methods & Properties interview questions

@staticmethod — a regular function inside the class namespace

A staticmethod receives no implicit first argument — it's a plain function that lives inside the class for organisational reasons only. It has no access to instance or class state unless you pass something in explicitly.

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

    def to_fahrenheit(self):                # instance method
        return self.celsius * 9/5 + 32

    @staticmethod
    def celsius_to_fahrenheit(c):           # no self, no cls
        return c * 9/5 + 32                 # pure conversion helper

Temperature.celsius_to_fahrenheit(100)      # 212.0 — no instance needed
Temperature(0).celsius_to_fahrenheit(100)   # same result — self is not passed

Use a staticmethod when the logic is related to the class conceptually (so you want it in the same namespace) but doesn't actually need to touch the class or any instance.

The subclass safety rule

The biggest practical difference between @classmethod and @staticmethod is subclass behaviour. A classmethod knows which (sub)class it was called on; a staticmethod doesn't:

class Shape:
    @classmethod
    def default(cls):
        return cls()          # builds the right subtype

    @staticmethod
    def default_bad():
        return Shape()        # always Shape, never the subclass

class Circle(Shape):
    pass

type(Circle.default())        # Circle  — correct
type(Circle.default_bad())    # Shape   — wrong

Rule of thumb: any factory or constructor method that subclasses might inherit should be a @classmethod, never a @staticmethod.

The decision rule

Answer two questions:

  1. Does the method need access to self (instance state)? → Instance method.
  2. Does the method need to create instances of the correct (sub)class or access class-level state, but not a specific instance?@classmethod.
  3. Is the method a utility helper that doesn't touch self or cls at all?@staticmethod.
class User:
    role = "user"                          # class attribute

    def __init__(self, name, email):
        self.name = name                   # instance attribute
        self.email = email

    def greet(self):                       # instance method — uses self
        return f"Hi, I'm {self.name}"

    @classmethod
    def from_dict(cls, data):             # classmethod — factory from dict
        return cls(data["name"], data["email"])

    @staticmethod
    def is_valid_email(email):            # staticmethod — pure utility
        return "@" in email and "." in email

Recap

An instance method takes self and is the right default for any per-object behaviour. A @classmethod takes cls — use it for alternative constructors and class-level logic, always with cls(...) rather than the hard-coded class name so subclasses get the right type. A @staticmethod takes nothing implicit — use it for utility helpers that belong in the class namespace but genuinely don't interact with any instance or class state. When in doubt between the two non-instance options, prefer @classmethod if there's any chance a subclass will call it.

More ways to practice

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

or
Join our WhatsApp Channel