Question

@staticmethod vs @classmethod in Python Explained

pythonoopstatic-methodspython-decoratorsclass-method

Question

In Python, what is the difference between a method decorated with @staticmethod and one decorated with @classmethod?

For example, how do these two method types differ in:

  • how they are defined
  • what arguments they receive automatically
  • when they should be used
  • how they behave when called from a class or an instance

Short Answer

By the end of this page, you will understand how @staticmethod and @classmethod work in Python, what each one receives automatically, when to use each, and how they differ from regular instance methods. You will also see practical examples, common mistakes, and a small project that makes the distinction easy to remember.

Concept

In Python, methods inside a class are not all the same. The main difference between @staticmethod and @classmethod is what Python passes to them automatically.

A quick reminder of the three common method types:

  • Instance method: works with a specific object and receives self
  • Class method: works with the class itself and receives cls
  • Static method: receives nothing automatically

Instance method

A normal method inside a class usually looks like this:

class User:
    def greet(self):
        return "Hello"

When you call user.greet(), Python automatically passes the instance as the first argument. That first argument is usually named self.

Class method

A class method is defined with @classmethod:

class User:
    @classmethod
    def from_name(cls, name):
        return cls()

When you call User.from_name("Sam"), Python automatically passes the class itself as the first argument. That argument is usually named cls.

This is useful when the method needs to:

  • create instances in an alternative way
  • access or modify class-level data
  • work correctly with inheritance

Static method

A static method is defined with @staticmethod:

class User:
    @staticmethod
    def is_valid_name(name):
        return len(name) > 0

When you call User.is_valid_name("Sam"), Python does not pass self or cls. It behaves like a regular function placed inside the class namespace.

This is useful when the function:

  • logically belongs to the class
  • does not need instance data
  • does not need class data

Why this matters

Choosing the correct method type makes code easier to understand.

  • Use an instance method when you need object-specific data
  • Use a class method when you need class-level behavior
  • Use a static method when you want a utility function grouped with the class

In real programs, this affects readability, inheritance behavior, object creation patterns, and how reusable your code is.

Mental Model

Think of a class like a company.

  • An instance method talks to one employee: it gets self
  • A class method talks to the company itself: it gets cls
  • A static method is just a tool kept in the company office: it does not get either one automatically

Simple analogy

  • self = this specific object
  • cls = this class
  • @staticmethod = a helper function stored inside the class because it belongs there conceptually

For example:

  • "What is this user's email?" → instance method
  • "Create a user from a CSV row" → class method
  • "Check whether an email format looks valid" → static method

A good question to ask is:

Does this method need the object, the class, or neither?

  • Needs the object → instance method
  • Needs the class → class method
  • Needs neither → static method
Take Quiz

Syntax and Examples

Core syntax

class Example:
    def instance_method(self):
        return "instance"

    @classmethod
    def class_method(cls):
        return "class"

    @staticmethod
    def static_method():
        return "static"

Example: all three together

class Temperature:
    scale = "Celsius"

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

    def describe(self):
        return f"{self.value} degrees {self.scale}"

    @classmethod
    def freezing_point(cls):
        return cls(0)

    @staticmethod
    def celsius_to_fahrenheit(celsius):
        return (celsius * 9 / 5) + 32


weather = Temperature(25)

print(weather.describe())
print(Temperature.freezing_point().describe())
print(Temperature.celsius_to_fahrenheit(25))

Output:

25 degrees Celsius
0 degrees Celsius
77.0

What each method is doing

describe(self)

  • Uses instance data: self.value
  • Also accesses self.scale
  • This should be an instance method

freezing_point(cls)

  • Uses cls to create and return an object
  • This is a common class method pattern called an alternative constructor
  • If the class is subclassed, cls(...) creates the correct subclass instance

celsius_to_fahrenheit(celsius)

  • Does not need self or cls
  • It is just a helper function related to temperatures
  • This is a good use of @staticmethod

Calling from class and instance

class Demo:
    @classmethod
    def show_class(cls):
        return cls.__name__

    @staticmethod
    def show_text():
        return "hello"


d = Demo()

print(Demo.show_class())
print(d.show_class())
print(Demo.show_text())
print(d.show_text())

Both @classmethod and @staticmethod can be called from:

  • the class
  • an instance

But their meaning is different:

  • class method still receives the class automatically
  • static method still receives nothing automatically

Step by Step Execution

Consider this example:

class Book:
    category = "General"

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

    @classmethod
    def default_book(cls):
        return cls("Untitled")

    @staticmethod
    def is_valid_title(title):
        return len(title.strip()) > 0

Now trace these calls:

book = Book.default_book()
valid = Book.is_valid_title("Python Basics")

Step by step

1. Python reads the class definition

It creates the Book class.

  • category becomes a class attribute
  • __init__ becomes an instance method
  • default_book becomes a class method
  • is_valid_title becomes a static method

2. Book.default_book() is called

book = Book.default_book()

Because default_book is a class method:

  • Python automatically passes Book as cls
  • So inside the method, cls refers to Book

The method runs:

return cls("Untitled")

That becomes:

return Book("Untitled")

This creates a new Book object with:

  • self.title = "Untitled"

Now book stores that new instance.

3. Book.is_valid_title("Python Basics") is called

valid = Book.is_valid_title("Python Basics")

Because is_valid_title is a static method:

  • Python does not pass self
  • Python does not pass cls
  • Only the argument you provide is used

So the method receives:

  • title = "Python Basics"

It evaluates:

len(title.strip()) > 0
  • title.strip() gives "Python Basics"
  • its length is greater than 0
  • result is True

So valid becomes True.

Key observation

The class method can create objects using the class. The static method simply performs a related check without needing the class or an instance.

Real World Use Cases

Common uses for @classmethod

Alternative constructors

A class method is often used to create objects from different input formats.

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

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

Useful when reading:

  • JSON data from an API
  • rows from a CSV file
  • configuration files
  • database records

Class-level configuration

class AppConfig:
    debug = False

    @classmethod
    def enable_debug(cls):
        cls.debug = True

This affects the class itself, not one specific object.

Common uses for @staticmethod

Validation helpers

class User:
    @staticmethod
    def is_valid_age(age):
        return age >= 0

Conversion or formatting logic

class DateTools:
    @staticmethod
    def format_year(year):
        return f"Year: {year}"

Utility logic grouped with a class

Sometimes a function belongs conceptually near a class even though it does not need class state.

class PasswordRules:
    @staticmethod
    def has_min_length(password):
        return len(password) >= 8

In apps and APIs

  • @classmethod is useful for creating model objects from API responses
  • @staticmethod is useful for input checks and transformation helpers
  • @classmethod helps subclasses create the correct object type
  • @staticmethod keeps utility logic organized without needing external helper modules for very small tasks
Take Quiz

Real Codebase Usage

In real codebases, developers usually choose between these method types based on what the method needs to know.

Common @classmethod patterns

Alternative constructors

class Order:
    def __init__(self, order_id, total):
        self.order_id = order_id
        self.total = total

    @classmethod
    def from_api(cls, payload):
        return cls(payload["id"], payload["total"])

This keeps parsing logic close to the class.

Inheritance-friendly creation

class Animal:
    def __init__(self, name):
        self.name = name

    @classmethod
    def unnamed(cls):
        return cls("Unknown")

class Dog(Animal):
    pass

pet = Dog.unnamed()
print(type(pet).__name__)

Output:

Dog

Because cls is Dog, the returned object is a Dog, not just an Animal.

Factory-style methods

Developers often use class methods to provide named ways to create objects.

  • from_dict
  • from_json
  • from_string
  • default
  • empty

Common @staticmethod patterns

Validation helpers near the model

class Product:
    @staticmethod
    def is_valid_price(price):
        return price >= 0

Small transformation logic

class StringTools:
    @staticmethod
    def slugify(text):
        return text.lower().replace(" ", "-")

Guard clauses and validation

A static method is often used before object creation.

class Product:
    def __init__(self, name, price):
        if not self.is_valid_price(price):
            raise ValueError("Price must be non-negative")
        self.name = name
        self.price = price

    @staticmethod
    def is_valid_price(price):
        return price >= 0

Practical guideline

In real projects:

  • use @classmethod when object creation or class behavior is involved
  • use @staticmethod for related helper logic that needs no object or class context
  • use a normal function outside the class if the logic does not really belong to the class at all

Common Mistakes

1. Using @staticmethod when cls is needed

Broken example:

class Person:
    def __init__(self, name):
        self.name = name

    @staticmethod
    def create(name):
        return cls(name)

Problem:

  • cls does not exist in a static method

Fix:

class Person:
    def __init__(self, name):
        self.name = name

    @classmethod
    def create(cls, name):
        return cls(name)

2. Using @classmethod for logic that does not need the class

This works, but it is misleading:

class MathTools:
    @classmethod
    def add(cls, a, b):
        return a + b

If the method does not use cls, prefer @staticmethod:

class MathTools:
    @staticmethod
    def add(a, b):
        return a + b

3. Forgetting that static methods do not get self

Broken example:

class Car:
    def __init__(self, brand):
        self.brand = brand

    @staticmethod
    def show_brand():
        return self.brand

Problem:

  • self is not available in a static method

Fix:

class Car:
    def __init__(self, brand):
        self.brand = brand

    def show_brand(self):
        return self.brand

4. Confusing class attributes with instance attributes

class Counter:
    count = 0

    @classmethod
    def increment(cls):
        cls.count += 1

This changes the class attribute, shared across instances. It does not create separate counts per object.

5. Putting too many helpers inside classes

Sometimes beginners put every function into a class as a static method.

That can make code harder to organize.

Use a static method only when the function clearly belongs to the class. Otherwise, a normal module-level function may be better.

Comparisons

Method type comparison

Method typeFirst automatic argumentCan access instance data?Can access class data?Common use
Instance methodselfYesYesWork with one object
Class methodclsNot directlyYesAlternative constructors, class-level behavior
Static methodNoneNoNo, unless referenced manuallyUtility logic related to the class

@classmethod vs @staticmethod

Feature@classmethod@staticmethod
Receives class automatically?Yes, as clsNo
Receives instance automatically?NoNo
Good for creating objects?YesUsually no
Works well with inheritance?YesNot for class-aware creation
Good for helper functions?SometimesYes

Which one should you choose?

If your method needs...Use
object state like self.nameinstance method
class state or cls(...)@classmethod
neither object nor class data@staticmethod

@staticmethod vs normal function outside the class

OptionBest when
@staticmethodthe function clearly belongs to the class conceptually
normal functionthe function is general-purpose and not tied to one class
Take Quiz

Cheat Sheet

Quick rules

  • Instance method: first parameter is self
  • Class method: use @classmethod, first parameter is cls
  • Static method: use @staticmethod, no automatic first parameter

Syntax

class Example:
    def instance_method(self):
        pass

    @classmethod
    def class_method(cls):
        pass

    @staticmethod
    def static_method(x, y):
        return x + y

When to use which

  • Use instance methods for object-specific behavior
  • Use class methods for class-level behavior or alternative constructors
  • Use static methods for helper logic that belongs with the class

Memory tip

  • self = this object
  • cls = this class
  • static = no automatic object or class

Common pattern

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

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

    @staticmethod
    def is_valid_name(name):
        return len(name.strip()) > 0

Important edge case

A static method can still access the class by naming it directly:

class A:
    value = 10

    @staticmethod
    def show():
        return A.value

But this is not class-aware in the same way as cls, so it is less flexible for inheritance.

Best practice

If a method does not use self or cls, ask whether it should be:

  • a @staticmethod, or
  • a normal function outside the class

FAQ

What is the main difference between @staticmethod and @classmethod in Python?

@classmethod receives the class as the first argument, usually named cls. @staticmethod receives no automatic first argument.

When should I use @classmethod in Python?

Use it when the method needs the class itself, especially for alternative constructors like from_dict, from_json, or default.

When should I use @staticmethod in Python?

Use it for helper functions that belong to the class logically but do not need instance or class data.

Can I call a class method on an instance?

Yes. You can call both class methods and static methods from either the class or an instance.

Can a static method access class variables?

Not automatically. It does not receive cls, but it can still refer to the class by name directly if needed.

Is @staticmethod the same as a normal function?

Not exactly. It behaves similarly because it gets no automatic arguments, but it is stored inside the class namespace.

Why is @classmethod better for inheritance?

Because it receives cls, which refers to the actual class used to call the method. That allows subclass-aware object creation.

Should I always use @staticmethod for helper methods?

No. If the function does not really belong to the class, a regular function outside the class may be cleaner.

Take Quiz

Mini Project

Description

Build a small User class that demonstrates all three method styles: an instance method, a class method, and a static method. This project shows a realistic pattern where you validate input with a static method, create objects from external data with a class method, and display object data with an instance method.

Goal

Create a User class that can be built from a dictionary, validate email text, and describe a specific user instance.

Requirements

[ "Create a User class with name and email attributes", "Add an instance method that returns a readable description of the user", "Add a class method that creates a User from a dictionary", "Add a static method that checks whether an email contains an @ symbol", "Use all three methods in example code" ]

Take Quiz

Keep learning

Related questions

View more