Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
Python

@staticmethod vs @classmethod in Python

Understand the difference between @staticmethod and @classmethod in Python, when to use each, and how they behave with inheritance.

July 2026 4 min read 1 views 0 hearts

If you have spent any time in Python, you've probably come across those little @staticmethod and @classmethod decorators sitting above method definitions. They look almost identical, but they serve different purposes, and mixing them up can lead to weird bugs or code that just feels wrong.

Here is the simple truth. Both let you call a method without having an instance of the class. But one is a polite guest who doesn't care about the class itself, while the other always knows which class it belongs to, even if you call it from a subclass.

## The Quick Breakdown

@staticmethod is just a function that happens to live inside a class for organization. It doesn't receive any special first argument. You can think of it as a utility function that is grouped with the class because it makes sense logically.

@classmethod receives the class itself as the first argument (conventionally named cls). This means it can access and modify class-level attributes, and it can be used as an alternative constructor.

Let's look at a real scenario. Imagine you are building a system for a library at Pythonskillset. You have a Book class.

class Book:
    late_fee_per_day = 0.50  # class-level attribute

    def __init__(self, title, author):
        self.title = title
        self.author = author
        self.days_borrowed = 0

    def calculate_late_fee(self):
        # instance method - needs self
        return self.days_borrowed * Book.late_fee_per_day

    @staticmethod
    def is_valid_isbn(isbn):
        # no self, no cls. Just a utility.
        return len(isbn) == 13 and isbn.isdigit()

    @classmethod
    def create_from_csv(cls, csv_string):
        # takes cls, so it can return a Book instance
        title, author = csv_string.strip().split(',')
        return cls(title, author)

Now see how they behave differently.

# Static method - no connection to class or instance
Book.is_valid_isbn("9781234567890")  # Returns True

# Class method - knows its class, can be used as alternative constructor
book = Book.create_from_csv("The Great Gatsby,F. Scott Fitzgerald")
print(book.title)  # "The Great Gatsby"

# Instance method - requires an instance
new_book = Book("1984", "George Orwell")
new_book.days_borrowed = 14
print(new_book.calculate_late_fee())  # 7.0

## Why Does The Difference Matter?

The key distinction becomes obvious when inheritance enters the picture. If you have a subclass of Book called Ebook:

class Ebook(Book):
    late_fee_per_day = 0.25  # Override class attribute

# Static method doesn't care about inheritance
Ebook.is_valid_isbn("123")  # Still calls Book's version, but it doesn't matter because it's a utility

# Class method respects inheritance
ebook = Ebook.create_from_csv("Digital Fortress,Dan Brown")
type(ebook)  # <class '__main__.Ebook'> - it creates an Ebook, not a Book

That cls parameter in the classmethod automatically refers to whatever class you call it on. If you had used Book(...) directly inside create_from_csv instead of cls(...), calling it on Ebook would still return a Book object, which is probably not what you want.

## When To Use Each One

Use @staticmethod when: - The method does not need access to the class or instance. - It performs a utility function that is conceptually related to the class but does not depend on its state. - You want to keep your module namespace clean but group related functions.

Use @classmethod when: - You need an alternative constructor that creates instances of the class. - The method needs to access or modify class-level attributes. - You want to implement a pattern where subclasses can customize behavior simply by inheriting and overriding class-level data.

A common pattern I see in real projects at Pythonskillset is using @classmethod for factory methods that parse different input formats, and @staticmethod for validation helpers.

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

    @staticmethod
    def is_valid_username(name):
        return name.isalnum() and len(name) >= 3

    @classmethod
    def from_email_string(cls, email_string):
        # Parse "username@domain.com" style input
        username = email_string.split('@')[0]
        return cls(username, email_string)

## Common Pitfall To Avoid

Do not use @staticmethod when you actually need the class. If you find yourself writing ClassName.some_attribute inside a staticmethod, you probably want a classmethod instead. Also, avoid using @classmethod for simple utility functions that don't need the class — it adds unnecessary overhead and confuses the intent.

The beauty of Python is that these decorators give you clear intent. When someone reads your code, @staticmethod says "this is just a function that lives here for organization". @classmethod says "this method respects class hierarchy and can be overridden meaningfully". Use them right, and your code becomes more readable and maintainable.

The next time you are writing a method that does not use self, ask yourself: does it need the class, or is it just a standalone utility? Your answer decides which decorator you need.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.