Question
Python @classmethod vs @staticmethod Explained for Beginners
Question
What do @classmethod and @staticmethod mean in Python, and how are they different? When should they be used, why are they useful, and how do you write them correctly?
I understand that @classmethod somehow relates a method to the class rather than an object instance, but I am not clear on what that really means in practice. I also want to understand why these decorators are needed at all. Why not just define methods normally without using @classmethod, @staticmethod, or any other @ decorators?
Short Answer
By the end of this page, you will understand the difference between instance methods, class methods, and static methods in Python. You will learn what self and cls mean, why @classmethod and @staticmethod exist, when to use each one, and how these choices affect inheritance, object creation, and code organization.
Concept
In Python, methods inside a class are not all the same. The main difference is what gets passed automatically as the first argument.
There are three common method types:
-
Instance methods
- Defined normally.
- Receive the current object as the first argument, usually named
self. - Used when the method needs to read or change data stored in a specific object.
-
Class methods
- Marked with
@classmethod. - Receive the class itself as the first argument, usually named
cls. - Used when the method needs to work with class-level data or create objects in an alternative way.
- Marked with
-
Static methods
- Marked with
@staticmethod. - Do not receive
selforclsautomatically. - Used when the function logically belongs inside the class, but does not need instance data or class data.
- Marked with
Why decorators are needed
Python needs a way to know how a method should behave when it is called.
- A normal method becomes an instance method.
@classmethodtells Python: "Pass the class as the first argument."@staticmethodtells Python: "Do not pass anything automatically."
Without these decorators, Python would treat the method as a normal instance method.
Why this matters
Choosing the right method type makes your code:
- easier to understand
- easier to maintain
- better for inheritance
- more explicit about what data a method depends on
For example:
- If a method needs
self.name, it should be an instance method. - If a method needs
cls.default_timeout, it should be a class method. - If a method just validates a string and does not need object or class state, it can be a static method.
Mental Model
Think of a class like a blueprint for making objects.
- An instance method is like talking to one specific product made from the blueprint.
- Example: "What is this user's email?"
- A class method is like talking to the blueprint itself.
- Example: "Make a new user from this CSV row."
- A static method is like a tool stored in the blueprint's toolbox.
- It belongs near the class because it is related, but it does not need the blueprint or any specific product.
Another way to remember it:
self= this objectcls= this class@staticmethod= no automatic object or class argument
Syntax and Examples
Core syntax
class Example:
class_value = 10
def instance_method(self):
return f"Instance method: {self}"
@classmethod
def class_method(cls):
return f"Class method: {cls.class_value}"
@staticmethod
def static_method(x, y):
return x + y
Example with all three
class User:
default_role = "member"
def __init__(self, name, role=None):
self.name = name
self.role = role or User.default_role
def describe(self):
return f"{self.name} is a {self.role}"
@classmethod
def guest(cls, name):
return cls(name, role="guest")
@staticmethod
def is_valid_name(name):
return isinstance(name, str) and len(name.strip()) > 0
How to use it
user = User("Ava")
print(user.describe())
print(User.guest("Sam").describe())
print(User.is_valid_name("Mia"))
What each part does
describe(self)uses data from a specificUserobject.guest(cls, name)creates a newUserin an alternative way.is_valid_name(name)is a helper function related toUser, but it does not needselforcls.
Why cls(...) is important
Inside a class method, using cls(...) instead of the class name directly supports inheritance:
class Admin(User):
pass
admin = Admin.guest("Jordan")
print(type(admin))
This creates an Admin object, not a User object, because cls refers to the class used to call the method.
Step by Step Execution
Consider this code:
class Counter:
total_created = 0
def __init__(self):
Counter.total_created += 1
@classmethod
def how_many(cls):
return cls.total_created
@staticmethod
def add(a, b):
return a + b
Now run:
c1 = Counter()
c2 = Counter()
print(Counter.how_many())
print(Counter.add(3, 4))
Step by step
1. c1 = Counter()
- Python creates a new
Counterobject. __init__runs.Counter.total_createdbecomes1.
2. c2 = Counter()
- Another
Counterobject is created. __init__runs again.Counter.total_createdbecomes2.
3. Counter.how_many()
- Because
how_manyhas@classmethod, Python passes the classCounteras the first argument. - So this is roughly like:
Counter.how_many(Counter)
- Inside the method,
cls.total_createdis2. - The method returns
2.
4. Counter.add(3, 4)
- Because
addhas@staticmethod, Python passes nothing automatically. - It behaves like a regular function stored inside the class namespace.
- It returns
7.
Key observation
how_manyknows about the class.adddoes not know about the class or any object.- A normal instance method would need an object first.
Real World Use Cases
When instance methods are used
- Updating a shopping cart item
- Changing a user's password
- Formatting data from a specific record
- Reading or modifying object state
When class methods are used
- Alternative constructors
- Create an object from JSON, CSV, environment variables, or database rows
- Working with class-level configuration
- Access shared settings or counters
- Inheritance-friendly factories
- Return the correct subclass automatically using
cls(...)
- Return the correct subclass automatically using
Example:
class Config:
def __init__(self, host, port):
self.host = host
self.port = port
@classmethod
def from_dict(cls, data):
return cls(data["host"], data["port"])
When static methods are used
- Validation helpers
- Formatting helpers
- Conversion logic closely related to a class
- Utility functions that make sense to keep near the class
Example:
class Email:
@staticmethod
def is_valid(address):
return "@" in address
This function is related to emails, so placing it inside Email can improve organization.
Real Codebase Usage
In real projects, developers often choose between these method types based on what the method depends on.
Common patterns
Instance methods for object behavior
class Order:
def __init__(self, items):
self.items = items
def total(self):
return sum(item["price"] for item in self.items)
This uses self.items, so it should be an instance method.
Class methods as alternative constructors
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
@classmethod
def from_string(cls, text):
name, price = text.split(",")
return cls(name, float(price))
This is very common in codebases that parse files, API responses, or configuration values.
Static methods for validation and transformation
class PasswordRules:
@staticmethod
def long_enough(password):
return len(password) >= 8
Guard clauses and validation
A static method is often used for small checks:
class User:
@staticmethod
def is_valid_age(age):
return isinstance(age, int) and age >= 0
Inheritance-friendly factories
class Animal:
def __init__(self, name):
self.name = name
@classmethod
def unnamed(cls):
return cls("Unknown")
class Dog(Animal):
pass
pet = Dog.unnamed()
Because unnamed uses cls, calling it on Dog creates a Dog.
Practical rule
Ask this question:
- Does it need object data? Use an instance method.
- Does it need class data or create objects? Use a class method.
- Does it need neither, but still belong conceptually to the class? Use a static method.
Common Mistakes
1. Using @staticmethod when you need class access
Broken code:
class Report:
format_type = "PDF"
@staticmethod
def default_format():
return cls.format_type
Problem:
clsdoes not exist in a static method.
Fix:
class Report:
format_type = "PDF"
@classmethod
def default_format(cls):
return cls.format_type
2. Forgetting self in an instance method
Broken code:
class User:
def greet():
return "Hello"
Problem:
- Instance methods automatically receive the object.
- Python will raise a
TypeErrorwhen called on an instance.
Fix:
class User:
def greet(self):
return "Hello"
3. Using the class name instead of cls inside a class method
Less flexible code:
class Person:
@classmethod
def anonymous(cls):
return Person("Anonymous")
Problem:
- This can break inheritance expectations.
Better:
class Person:
def __init__(self, name):
self.name = name
@classmethod
def anonymous(cls):
return cls("Anonymous")
4. Using @classmethod when a normal function would be clearer
Not every helper needs to be inside a class.
class MathTools:
@classmethod
def add(cls, a, b):
return a + b
If the method does not use cls, self, or class organization meaningfully, a plain function may be better.
5. Thinking @classmethod is mainly about inheritance
@classmethod does work well with inheritance, but that is not its only purpose.
It mainly means: the method receives the class instead of an instance.
Inheritance is a useful consequence, not the whole definition.
Comparisons
Method types compared
| Method type | Decorator | First automatic argument | Can access instance data? | Can access class data? | Common use |
|---|---|---|---|---|---|
| Instance method | None | self | Yes | Yes, through self or class name | Normal object behavior |
| Class method | @classmethod | cls | Not directly | Yes | Alternative constructors, class-level behavior |
| Static method | @staticmethod | None | No | No automatic access | Utility helpers related to the class |
Instance method vs class method
| Question | Instance method | Class method |
|---|---|---|
| Works on one specific object? | Yes | No |
Can create objects using cls(...)? | No | Yes |
| Best for object state? | Yes | No |
| Best for shared class logic? | Sometimes | Yes |
Static method vs plain function
| Option | When to use it |
|---|---|
| Static method | When the function is strongly related to the class domain |
| Plain function | When the logic is general-purpose and not tied to the class |
Important comparison with normal methods
If you write this:
class Example:
def hello(self):
return "hi"
Python treats hello as an instance method. That means calling obj.hello() passes obj automatically as self.
If you do not want that behavior, you must use @classmethod or @staticmethod depending on your goal.
Cheat Sheet
Quick reference
Instance method
class A:
def method(self):
pass
- Default method type
- Receives
self - Use for object-specific behavior
Class method
class A:
@classmethod
def method(cls):
pass
- Receives
cls - Use for class-level logic
- Great for alternative constructors
- Prefer
cls(...)over hardcoding the class name
Static method
class A:
@staticmethod
def method(x, y):
pass
- Receives no automatic first argument
- Use for helper logic related to the class
- Cannot use
selforclsunless passed manually
Rules of thumb
- Needs instance data? → instance method
- Needs class data or creates instances? → class method
- Needs neither, but belongs near the class? → static method
Common names
selffor instance methodsclsfor class methods
Edge case reminder
A static method is not the same as a class method.
@classmethodgets the class automatically@staticmethodgets nothing automatically
FAQ
What is the difference between @classmethod and @staticmethod in Python?
A class method receives the class as cls. A static method receives no automatic argument at all. Use a class method when the logic depends on the class; use a static method when it does not.
Why use @classmethod instead of a normal method?
Use @classmethod when the method should work with the class itself rather than with one object instance. This is common for alternative constructors such as from_dict() or from_string().
Why use @staticmethod at all?
It helps group related helper logic inside a class. This can improve code organization when the function is clearly tied to the class concept.
Can a class method access instance variables?
Not directly. It receives cls, not self. It can only access class-level data unless you pass an instance manually.
Can a static method access class variables?
Not automatically. A static method does not receive cls or self. It can still access a class by name, but that removes some flexibility.
Is @classmethod inherited by subclasses?
Yes. Subclasses inherit class methods, and when a subclass calls one, cls refers to that subclass.
Should I always use @staticmethod for helper functions?
No. If the helper is general-purpose and not really part of the class concept, a plain function outside the class is often clearer.
What happens if I leave off @classmethod or @staticmethod?
Then Python treats the method as a normal instance method, which means it expects an instance and passes self automatically when called on an object.
Mini Project
Description
Build a small Book class that demonstrates all three method types. This project shows how one class can store object data, create objects in multiple ways, and keep related helper logic organized.
Goal
Create a Book class with an instance method, a class method, and a static method, then use each one correctly.
Requirements
- Create a
Bookclass withtitleandauthorattributes. - Add an instance method that returns a readable description of the book.
- Add a class method that creates a
Bookfrom a single string like"Dune|Frank Herbert". - Add a static method that checks whether a title is non-empty.
- Create at least two
Bookobjects and call all three method types.
Keep learning
Related questions
@staticmethod vs @classmethod in Python Explained
Learn the difference between @staticmethod and @classmethod in Python with clear examples, use cases, mistakes, and a mini project.
Add Rows to a Pandas DataFrame in Python
Learn how to add rows to a Pandas DataFrame, why repeated row appends are slow, and when to use loc, concat, or record lists.
Call a Function by Name in a Python Module
Learn how to call a function by name in a Python module using strings, getattr, and safe patterns for dynamic function dispatch.