Python has three method types, and the difference comes down to one question: what does Python pass as the first argument when you call the method? Instance methods (the default) receive the instance. Classmethods receive the class. Staticmethods receive nothing extra. Once that dispatch mechanism clicks, the decorator syntax (@classmethod, @staticmethod) becomes obvious, the factory method pattern explains itself, and the lingering "should I use staticmethod here?" question gets a clear answer. This guide explains the mechanism, shows the three canonical use cases (regular methods, factory methods, utility helpers), covers the inheritance behavior that makes cls uniquely valuable, and gives the honest test for when a staticmethod is actually a module function in disguise. It's one of 10 explainers in our Python OOP complete guide.

Key Takeaways

  • The difference is the first argument Python passes. Instance method gets the instance (self); classmethod gets the class (cls); staticmethod gets nothing extra.
  • Default is instance method. Use @classmethod for factory methods (alternative constructors); use @staticmethod rarely, for utilities tightly bound to a class.
  • The factory pattern is why classmethod exists: cls resolves to the actual class at call site, so subclasses get their own working factory without code duplication.
  • Most staticmethods could be module functions instead. Honest test: if you'd struggle to explain why it lives in the class, move it out.
  • Naming convention: factory methods start with from_ (from_dict, from_string, fromtimestamp). Follow it.
Method dispatch: what Python passes as the first argument What Python passes as the first argument INSTANCE METHOD · CLASSMETHOD · STATICMETHOD — DISPATCH EXPLAINED YOU WRITE PYTHON CALLS RECEIVES INSTANCE METHOD dog.bark() UNDER THE HOOD Dog.bark(dog) self the instance @CLASSMETHOD Dog.create("Rex") UNDER THE HOOD Dog.create(Dog, "Rex") cls the class @STATICMETHOD Dog.helper(42) UNDER THE HOOD Dog.helper(42) nothing no implicit arg THE PATTERN Calling obj.method(args) always translates to Class.method(...) under the hood. What changes is what gets inserted before args: the instance, the class, or nothing. READING THE DISPATCH The three method types only differ in one thing: what Python silently passes as the first argument. Once you see that, the decorators (@classmethod, @staticmethod) and the conventions (self, cls) explain themselves.
One dispatch rule, three variants. The decorator chooses what gets passed first.

Instance Method: The Default

Every method you define inside a class block is an instance method by default. Python passes the instance as the first argument. By convention you name that argument self, but it's just a positional parameter (see our OOP for beginners guide for the deeper explanation).
class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def bark(self):                      # Instance method
        print(f"{self.name}!")

    def describe(self):                  # Instance method
        return f"{self.name}, {self.age} years old"

rex = Dog("Rex", 4)
rex.bark()             # Rex!
print(rex.describe())  # Rex, 4 years old
Instance methods access:
  • Instance state via self.attribute (self.name, self.age)
  • Class state via self.class_attribute or type(self).class_attribute
  • Other instance methods via self.other_method()
This is the default and the most common method type. ~80% of your methods will be instance methods.

@classmethod: For Factory Methods (Alternative Constructors)

The killer feature of @classmethod is the alternative constructor pattern. You want to create instances of your class in more than one way:
from datetime import datetime

class User:
    def __init__(self, name, email, age):
        self.name = name
        self.email = email
        self.age = age

    @classmethod
    def from_dict(cls, data):
        return cls(data["name"], data["email"], data["age"])

    @classmethod
    def from_csv_row(cls, row):
        name, email, age = row.split(",")
        return cls(name.strip(), email.strip(), int(age))

    @classmethod
    def anonymous(cls):
        return cls("Anonymous", "anon@example.com", 0)

# Three different ways to create a User:
alice = User("Alice", "alice@ex.com", 30)              # Default constructor
bob = User.from_dict({"name": "Bob",
                      "email": "bob@ex.com", "age": 25})  # From dict
charlie = User.from_csv_row("Charlie,c@ex.com,40")     # From CSV
guest = User.anonymous()                                # Defaults
The PSF docs on classmethod describe this directly: classmethods are typically used "for the factory method pattern."

Why classmethod and not just a regular function?

This is the question that resolves the @classmethod existence question entirely. Inheritance.
class User:
    def __init__(self, name):
        self.name = name

    @classmethod
    def from_string(cls, s):
        return cls(s.strip().title())   # cls, not User!

class AdminUser(User):
    def grant_admin(self):
        return f"{self.name} is admin"

# Because we used cls (not User), AdminUser.from_string returns an AdminUser:
admin = AdminUser.from_string("  alice  ")
print(type(admin).__name__)    # AdminUser, not User
print(admin.grant_admin())     # Alice is admin
If we'd hardcoded return User(s.strip().title()), then AdminUser.from_string("alice") would still return a User instance, breaking the subclass. The cls parameter makes the factory polymorphic: it works correctly for every subclass without duplicating code.

This is the single biggest reason to use @classmethod instead of a module-level function for factories. See the guide on super().__init__() and MRO for the broader inheritance story.

Real-world classmethods in the standard library

Standard library classmethodWhat it does
datetime.fromtimestamp(ts)Creates datetime from POSIX timestamp
datetime.fromisoformat(s)Creates datetime from ISO 8601 string
dict.fromkeys(keys, value)Creates dict with given keys, all mapped to value
str.maketrans(x, y, z)Creates translation table for str.translate
Path.cwd() (pathlib)Creates Path from current working directory
Path.home() (pathlib)Creates Path from user home directory
Naming convention: factory methods conventionally start with from_ (from_dict, from_string, from_csv, from_json) or use clear factory-like names (anonymous, default, cwd, home).

@staticmethod: Utilities, Sometimes Justified

A staticmethod doesn't receive any implicit argument. It's just a function that happens to be defined inside the class. You access it via Class.method() or instance.method() — both work the same way.
class Order:
    def __init__(self, quantity, unit_price):
        if not Order.is_valid_quantity(quantity):
            raise ValueError("quantity must be positive")
        self.quantity = quantity
        self.unit_price = unit_price

    @staticmethod
    def is_valid_quantity(n):
        return isinstance(n, int) and n > 0

    @staticmethod
    def hex_to_rgb(h):                     # Pure utility, no state
        h = h.lstrip("#")
        return tuple(int(h[i:i+2], 16) for i in (0, 2, 4))
The legitimate cases for staticmethod are narrow:
  • Input validators tightly bound to the class (Order.is_valid_quantity(n))
  • Pure transformations conceptually attached to the class (Color.hex_to_rgb(s))
  • Constants-as-callables that just feel right inside the class namespace

The honest test for staticmethod

Most staticmethods are module functions in disguise. The test:

If you removed the class wrapper, would the function lose anything? If the answer is no, it should be a module-level function. The Diederich rule covers this directly: don't use a class as a namespace; modules are already namespaces.
# OVER-ENGINEERED — the class adds nothing
class StringHelpers:
    @staticmethod
    def reverse(s):
        return s[::-1]

    @staticmethod
    def capitalize_first(s):
        return s[0].upper() + s[1:]

StringHelpers.reverse("hello")

# IDIOMATIC — module-level functions
# In string_helpers.py:
def reverse(s):
    return s[::-1]

def capitalize_first(s):
    return s[0].upper() + s[1:]

# Usage:
from string_helpers import reverse
reverse("hello")
The staticmethod version costs an extra @staticmethod decorator on every function plus the requirement to import the class instead of the function. Skip it.

When staticmethod IS the right call

The genuine case: the function is so conceptually tied to the class that finding it OUTSIDE the class would surprise you. Order.is_valid_quantity fits because anyone working with Order would expect quantity validation to live there. Color.hex_to_rgb fits because color parsing belongs with the Color type. If you can imagine the function alone, without the class context, prefer a module function.

Comparison Table

PropertyInstance method@classmethod@staticmethod
First argumentself (instance)cls (class)nothing
Access instance state?YesNoNo
Access class state?Yes (via self.cls_attr)Yes (via cls.attr)No
Call from instance?YesYes (gets the class)Yes
Call from class?No (TypeError without self)YesYes
Inheritance-aware?YesYes (cls is the subclass)No
DecoratorNone (default)@classmethod@staticmethod
Primary useBehavior on instance stateFactory methods, alt constructorsUtilities tied to class namespace
Frequency in real code~80%~15%~5%

Three Use-Case Patterns

Pattern 1: Instance method for behavior on state

class BankAccount:
    def __init__(self, balance):
        self.balance = balance

    def deposit(self, amount):           # Modifies self.balance
        self.balance += amount

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("Insufficient funds")
        self.balance -= amount
This is the default and the most common. State and behavior naturally bundle.

Pattern 2: classmethod for factories with multiple input formats

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

    @classmethod
    def from_string(cls, s):             # "2026-06-17" -> Date(2026, 6, 17)
        year, month, day = map(int, s.split("-"))
        return cls(year, month, day)

    @classmethod
    def today(cls):                      # No args needed
        import datetime
        d = datetime.date.today()
        return cls(d.year, d.month, d.day)

Pattern 3: staticmethod for tightly-bound utilities

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

    @staticmethod
    def c_to_f(c):                       # Pure: C -> F
        return c * 9 / 5 + 32

    @staticmethod
    def f_to_c(f):                       # Pure: F -> C
        return (f - 32) * 5 / 9

    def in_fahrenheit(self):
        return Temperature.c_to_f(self.celsius)

# c_to_f is conceptually part of Temperature; calling it without
# instantiating Temperature still makes sense:
Temperature.c_to_f(100)        # 212.0
Honest reality check: the c_to_f and f_to_c functions above could also live in a temperature.py module as plain functions. They're staticmethods only because someone decided "all temperature conversion stays in the Temperature class." Both choices are defensible.

The Common Confusion: When to Use Which

A decision rule that fits on one note:
  1. Does the method need self? Yes → instance method (default). Done.
  2. Does it create new instances or need to know the class? Yes → @classmethod.
  3. Is it a utility that conceptually belongs with the class? Yes → consider @staticmethod. But ask: would this be cleaner as a module function?
  4. None of the above? It might not belong on the class at all. See when to use OOP in Python.

Common Mistakes

Forgetting the decorator on a factory

# Wrong — cls is undefined, fails at call time
class User:
    def from_dict(cls, data):           # Missing @classmethod!
        return cls(data["name"])

# Right
class User:
    @classmethod
    def from_dict(cls, data):
        return cls(data["name"])
Without @classmethod, Python treats from_dict as an instance method, and User.from_dict({}) fails because no instance is passed.

Using staticmethod when you needed classmethod

# Wrong — staticmethod can't know which class called it
class Shape:
    @staticmethod
    def default():
        return Shape()         # Hardcoded; subclasses get wrong type!

class Circle(Shape):
    pass

# Circle.default() returns a Shape, not a Circle — bug!

# Right
class Shape:
    @classmethod
    def default(cls):
        return cls()           # cls IS Circle when called via Circle.default()

Calling a classmethod and expecting instance access

class Counter:
    count = 0

    @classmethod
    def increment(cls):
        cls.count += 1
        # cls.name  <-- ERROR: classmethod has no instance, no name attribute

# Classmethods can only access class state, never instance state.

Frequently Asked Questions

What is the difference between staticmethod, classmethod, and instance method in Python?

Instance methods (the default) receive the instance as the first argument, conventionally named self, and can access both instance state (self.x) and class state. Class methods (decorated with @classmethod) receive the class as the first argument, conventionally named cls, and can access class state but not instance state — they're used primarily for factory methods like User.from_dict(d) or datetime.fromtimestamp(ts). Static methods (decorated with @staticmethod) receive nothing extra; they're utility functions that happen to be defined inside the class for namespacing. The dispatch mechanism: obj.method() translates to Class.method(obj) for instance methods; Class.method() translates to Class.method(Class) for classmethods; obj.utility() translates to Class.utility() with no extra argument for staticmethods.

When should I use a classmethod?

Use @classmethod when you need an alternative constructor (a factory method that creates instances in a different way than the default __init__). The canonical examples are datetime.fromtimestamp(ts), dict.fromkeys(keys, value), and your own User.from_dict(data), User.from_json(s), Vector.from_polar(r, theta). The key reason to use classmethod instead of hardcoding the class name in a regular function: classmethod receives cls automatically, so when you subclass, the factory creates instances of the SUBCLASS, not the original class. Naming convention: prefix factory methods with from_ (from_string, from_dict, from_csv, from_user_input).

When should I use a staticmethod?

Rarely. The honest answer: most staticmethods could be module-level functions instead. Reach for @staticmethod when you have a small utility function that's TIGHTLY related to a class but doesn't need access to class or instance state — the namespacing makes it discoverable as Class.helper() rather than helper(). Common legitimate cases: input validators (Order.is_valid_quantity(n)), simple transformations (Color.hex_to_rgb(s)), and pure helpers conceptually tied to a class. If you'd struggle to explain WHY the function lives inside the class rather than at module level, it probably shouldn't be a staticmethod.

Why does classmethod use cls instead of just hardcoding the class name?

Because of inheritance. If you write @classmethod def from_dict(cls, d): return cls(**d), then SubClass.from_dict({}) creates a SubClass instance because cls IS SubClass at that call site. If you hardcoded the name like return User(**d), calling SubUser.from_dict({}) would still create a User, not a SubUser. The cls parameter makes factory methods polymorphic: each subclass gets its own working factory without copy-pasting the implementation. This is the single biggest reason classmethod exists rather than just using module functions for factories.

Can a classmethod call a staticmethod or vice versa?

Yes, freely. A classmethod can call a staticmethod via cls.static_helper() or Class.static_helper() and vice versa. A classmethod can also call instance methods if it has an instance to call them on. An instance method can call both classmethods and staticmethods through self.classmethod() (which forwards to the class) or self.staticmethod(). There's no restriction on which method type can call which; the restrictions are about which DATA each method type can access (instance state, class state, neither).

The Bottom Line: First Argument Decides Everything

The three method types differ in exactly one thing: what Python silently passes as the first argument. Instance method gets the instance. Classmethod gets the class. Staticmethod gets nothing. Once that dispatch model clicks, the use cases follow: instance methods for behavior on state (default), classmethods for factory methods that need to be inheritance-aware, staticmethods for tightly-bound utilities (rare). When in doubt, default to instance method. When you need a factory, @classmethod with a from_ name. When you reach for @staticmethod, ask first if it should be a module function. The next entry covers super().__init__() and MRO — the inheritance mechanics that make classmethods uniquely valuable. Or browse the full Python OOP guide.

Practice Method Types Until They're Reflex

CodeGym's Python track turns the three method types into reflex through hands-on tasks structured around real factory patterns, validators, and class state. 800+ tasks across 62 levels with AI validators that grade every submission and AI mentors that explain when you reached for the wrong method type. First level free; full plan on the pricing page.