Python gives you three distinct method types inside a class: instance methods, static methods, and class methods. Of the three, @classmethod is the one that trips people up the longest — not because the syntax is complicated, but because the reason it exists is subtle. This article explains exactly what @classmethod does at the language level, why cls is not just a renamed self, and the specific patterns where it is the correct tool and nothing else will do.
Quick Answer: What Does @classmethod Do?
The @classmethod decorator defines a method that receives the class itself as the first argument instead of an instance. This argument is conventionally named cls.
Unlike instance methods, which operate on a specific object, class methods operate on the class as a whole. They are commonly used for alternative constructors, factory methods, operations that modify class-level state, and behavior that must remain inheritance-aware.
class User:
def __init__(self, name):
self.name = name
@classmethod
def from_csv(cls, row):
name = row.split(",")[0]
return cls(name)
# Constructs a User without calling __init__ directly
user = User.from_csv("Alice,Engineering")
print(user.name) # Alice
Calling User.from_csv() constructs a new User instance without directly invoking the constructor. Because the method uses cls(...) rather than User(...), subclasses that inherit this method will automatically construct the correct type.
Python's object model is built on a concept called the descriptor protocol. Decorators like @classmethod, @staticmethod, and even @property are not magic keywords — they are built-in descriptor objects that alter how Python resolves attribute access on a class. Understanding that one sentence will make everything else in this article click into place.
What Is Python @classmethod?
In Python, @classmethod is a built-in decorator that converts a method into one that receives the class itself as the first argument instead of an instance. The method receives the class object through the cls parameter, allowing it to construct new instances, access class-level attributes, and behave polymorphically across subclasses.
Unlike instance methods, which receive self, and static methods, which receive no automatic arguments, class methods are bound to the class object through Python's descriptor protocol. When a class method is called, Python automatically passes the class as the first argument.
This behavior makes @classmethod especially useful for:
- Alternative constructors (factory methods)
- Operations that depend on class-level state
- Inheritance-safe object construction
- Framework patterns that rely on subclass polymorphism
The three method types in Python differ only in how the first argument is bound. Instance methods receive an instance (self). Class methods receive the class (cls). Static methods receive nothing automatically. Every pattern and use case covered in this article follows from that single distinction.
What @classmethod Does Under the Hood
When Python executes a class body, every function defined inside it becomes a non-data descriptor stored in the class's __dict__. A descriptor is simply any object that implements __get__, __set__, or __delete__. A regular function has a __get__ method, which is why accessing it on an instance produces a bound method with the instance automatically inserted as the first argument (self).
@classmethod wraps that function in a different descriptor. According to the official Python Descriptor HowTo Guide, when the class method descriptor's __get__ is invoked, it returns the function bound to the class object itself rather than to an instance. The pure-Python equivalent looks like this:
import functools
from types import MethodType
class ClassMethod:
"""Equivalent to the built-in classmethod descriptor."""
def __init__(self, f):
self.f = f
functools.update_wrapper(self, f)
def __get__(self, obj, cls=None):
if cls is None:
cls = type(obj)
# Bind the function to the class, not the instance
return MethodType(self.f, cls)
That is all @classmethod is: a descriptor whose __get__ always binds to the class. Whether you call the method on the class directly (MyClass.method()) or on an instance (obj.method()), the first argument received by the function is always the class. The CPython implementation of classmethod can be examined directly in the interpreter source code for those interested in how the C-level descriptor works.
The binding transformation is what makes this concrete. When Python resolves method access, it transforms the call depending on the method type:
# Regular method binding:
# instance.method() -> method(instance) first arg = the instance
# Class.method() -> unbound, requires explicit instance
# Classmethod binding:
# instance.cm() -> cm(Class) first arg = the class
# Class.cm() -> cm(Class) first arg = the class
# Staticmethod binding:
# instance.sm() -> sm() no automatic first arg
# Class.sm() -> sm() no automatic first arg
The key insight here is that @classmethod rewires Python's method binding so the class object is injected as the first argument regardless of how the method is accessed. It does not change the function itself — it changes how Python binds the function when it is looked up as an attribute.
The cls name is a convention, not a requirement. Python does not enforce it. You could write def create(klass, ...) and it would work identically. The community convention exists to signal intent clearly, and you should follow it.
The built-in classmethod() function and the @classmethod decorator are the same thing. Writing @classmethod above a method definition is syntactic sugar for calling classmethod(func) on the function and rebinding the name. Python documentation notes that the older explicit form — MyClass.method = classmethod(MyClass.method) — is considered un-Pythonic; the decorator form is the correct modern style.
"This behavior is useful whenever the method only needs to have a class reference and does not rely on data stored in a specific instance." — Python Descriptor HowTo Guide, docs.python.org
Why Does Python Need @classmethod at All?
Understanding the descriptor mechanics is useful, but the deeper question is: why does this feature exist in the first place? The answer is polymorphic construction. Without cls, a factory method would have no way to know which class invoked it. If you wrote a factory as a @staticmethod, it would always return an instance of the base class because it receives no class reference at all. A class method receives the calling class as cls, which means a factory defined on a parent class can produce the correct subclass type automatically. That single capability — preserving polymorphism through inheritance — is the entire reason @classmethod exists. Everything else it enables (class-level state access, registry patterns, configuration hooks) follows from the same mechanism.
Before reading the answer, take a moment to reason about what the following code will print. Understanding @classmethod becomes much clearer when you trace how Python binds the first argument.
class Example:
name = "Base"
@classmethod
def identify(cls):
return cls.name
class Child(Example):
name = "Child"
print(Child.identify())
What do you expect the output to be?
Answer:
Child
The method receives the class object that invoked it. Because Child calls the method, the cls parameter refers to Child, not Example. This behavior is what allows class methods to support polymorphic factories and inheritance-aware logic — the concepts covered in the sections that follow.
The Three Method Types, Side by Side
To understand when to use @classmethod, you need a clear picture of what separates it from the other two method forms. The fundamental difference is what gets automatically passed as the first argument.
class Connection:
default_timeout = 30 # class-level attribute
def __init__(self, host, port):
self.host = host # instance attribute
self.port = port # instance attribute
# Instance method: receives the specific object (self)
def describe(self):
return f"Connected to {self.host}:{self.port}"
# Class method: receives the class itself (cls)
@classmethod
def from_url(cls, url):
host, port = url.split(":")
return cls(host, int(port))
# Static method: receives nothing automatically
@staticmethod
def validate_port(port):
return 1 <= port <= 65535
# All three called on the class or an instance:
conn = Connection.from_url("db.internal:5432")
print(conn.describe()) # "Connected to db.internal:5432"
print(Connection.validate_port(5432)) # True
The distinctions, stated precisely:
- Instance method — receives
self, which is the specific instantiated object. It can read and modify both instance attributes and class attributes. - Class method — receives
cls, which is the class object. It can read and modify class-level attributes but has no reference to any particular instance. - Static method — receives nothing automatically. It has no access to either instance or class state. It is a plain function that lives in the class namespace for organizational reasons.
Quick-Reference Comparison
| Capability | Instance Method | Class Method | Static Method |
|---|---|---|---|
Receives instance (self) |
Yes | No | No |
Receives class (cls) |
No | Yes | No |
| Can modify instance state | Yes | No | No |
| Can modify class state | Indirectly | Yes | No |
| Supports polymorphic factories | No | Yes | No |
| Inherits correctly in subclasses | Yes | Yes (via cls) |
No class awareness |
A useful decision rule: if your method needs self (instance state), write a normal method. If it needs cls (class state or construction), use @classmethod. If it needs neither, use @staticmethod. That said, if a static method has no meaningful relationship to the class beyond namespace convenience, consider whether a module-level function would be a cleaner fit — though static methods are perfectly appropriate when the function is semantically tied to the class's domain.
The Same Problem Solved Three Ways
A comparison table is useful, but the real clarity comes from seeing all three method types applied to the same task. Consider constructing a User object from a CSV row. This single example reveals why @classmethod exists.
Instance Method (Wrong Context)
class User:
def __init__(self, name):
self.name = name
def from_csv(self, row):
name = row.split(",")[0].strip()
return User(name)
# Problem: you need an existing User to create a new one
existing = User("placeholder")
new_user = existing.from_csv("Alice,Engineering")
This is a poor fit because object creation logic does not belong to an already-existing instance. You must first create a User object in order to create another one, which is semantically backward.
Static Method (Works but Breaks Inheritance)
class User:
def __init__(self, name):
self.name = name
@staticmethod
def from_csv(row):
name = row.split(",")[0].strip()
return User(name)
class Admin(User):
pass
obj = Admin.from_csv("Alice")
print(type(obj).__name__) # User, NOT Admin
This works for the base class but introduces a subtle problem: the method hardcodes the class name. If a subclass calls this method, it still constructs a User rather than the subclass. Polymorphism is silently lost.
Class Method (Correct Design)
class User:
def __init__(self, name):
self.name = name
@classmethod
def from_csv(cls, row):
name = row.split(",")[0].strip()
return cls(name)
class Admin(User):
pass
obj = Admin.from_csv("Alice")
print(type(obj).__name__) # Admin
This version is inheritance-safe. The cls parameter refers to the calling class, meaning subclasses automatically construct their own type. The factory method is defined once on the parent and works correctly for every subclass without modification.
The @classmethod decorator does not change the function itself. It changes how Python binds the first argument when the method is accessed. That binding change is the entire mechanism behind polymorphic factories, alternative constructors, and class-level operations.
Python @classmethod vs @staticmethod
The key difference between @classmethod and @staticmethod is whether Python automatically passes the class as the first argument.
- @classmethod receives the class object as
cls. It can access class attributes, construct new instances usingcls(...), and behave polymorphically across subclasses. - @staticmethod receives no automatic arguments. It behaves like a normal function that is simply namespaced inside a class.
Class methods can modify class-level state, serve as alternative constructors, and participate in inheritance hierarchies. Static methods are organizational conveniences — they group a function with a class for readability but carry no binding behavior. If a method does not use cls, it should either be a @staticmethod or a standalone module-level function.
Factory Methods: The Primary Use Case
What happens when object creation requires logic that does not belong in __init__? Python does not support method overloading. You cannot define two versions of __init__ that accept different argument signatures; the second definition simply replaces the first. Class methods solve this problem elegantly by acting as named alternative constructors — a pattern known in software design as the Factory Method.
Factory methods allow a class to provide multiple construction paths without bloating __init__ with conditional logic. Each factory encapsulates its own construction logic, keeps the primary constructor clean, and — because it uses cls(...) — supports subclass polymorphism automatically. You will see this pattern expressed as named constructors like User.from_json(), User.from_csv(), or User.from_database() in well-designed Python codebases.
The standard library uses this pattern extensively. The Python Descriptor HowTo Guide cites dict.fromkeys() as a canonical example: it creates a new dictionary from an iterable of keys, using a class method so that subclasses of dict can inherit the behavior and produce the correct type.
import datetime
class Employee:
def __init__(self, name, department, hire_date):
self.name = name
self.department = department
self.hire_date = hire_date
# Alternative constructor: create from a CSV row string
@classmethod
def from_csv_row(cls, row):
name, department, date_str = row.split(",")
hire_date = datetime.date.fromisoformat(date_str.strip())
return cls(name.strip(), department.strip(), hire_date)
# Alternative constructor: create a "new hire" with today's date
@classmethod
def new_hire(cls, name, department):
return cls(name, department, datetime.date.today())
def __repr__(self):
return f"Employee({self.name!r}, {self.department!r}, {self.hire_date})"
# Using the standard constructor
alice = Employee("Alice", "Engineering", datetime.date(2022, 3, 1))
# Using the CSV factory
bob = Employee.from_csv_row("Bob, Marketing, 2023-07-15")
# Using the new-hire shortcut
carol = Employee.new_hire("Carol", "Design")
print(alice) # Employee('Alice', 'Engineering', 2022-03-01)
print(bob) # Employee('Bob', 'Marketing', 2023-07-15)
print(carol) # Employee('Carol', 'Design', <today's date>)
Notice that each factory method calls cls(...) rather than Employee(...). This is not cosmetic. The reason it matters enormously becomes clear in the next section.
A Real-World Factory: Configuration-Based Construction
Factory methods become especially valuable in production codebases where objects are constructed from external configuration rather than hardcoded values. A common pattern in applications that follow twelve-factor configuration principles is constructing service objects from environment variables:
import os
class Database:
def __init__(self, host, port, dbname):
self.host = host
self.port = port
self.dbname = dbname
@classmethod
def from_env(cls):
return cls(
host=os.getenv("DB_HOST", "localhost"),
port=int(os.getenv("DB_PORT", "5432")),
dbname=os.getenv("DB_NAME", "app")
)
def __repr__(self):
return f"{type(self).__name__}({self.host}:{self.port}/{self.dbname})"
# In production code:
db = Database.from_env()
# In tests, the standard constructor still works:
test_db = Database("localhost", 5432, "test_db")
The factory isolates environment-reading logic from the constructor, keeps testing straightforward (tests call the standard constructor with known values), and remains inheritance-safe because it uses cls(...). This is the kind of pattern that appears across frameworks like Django, Flask, and SQLAlchemy wherever objects need to be configured from external sources.
How @classmethod Differs From __new__
A question that frequently comes up when discussing alternative constructors is: why not override __new__ instead? The two serve different purposes. __new__ is the method responsible for allocating memory and creating the raw instance object before __init__ initializes it. It is the right tool when you need to control instance creation itself — for example, implementing a singleton, caching instances, or returning an object of a different type entirely. A @classmethod factory, by contrast, provides a named entry point that calls the normal constructor (cls(...)) with different arguments or from a different data source. The factory does not interfere with how instances are allocated; it simply gives callers a more convenient or more descriptive way to reach the constructor.
# __new__ controls allocation: singleton pattern
class SingletonConnection:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, connection_string):
self.connection_string = connection_string
# @classmethod provides alternate construction paths
class ConfiguredConnection:
def __init__(self, host, port, dbname):
self.host = host
self.port = port
self.dbname = dbname
@classmethod
def from_url(cls, url):
# Parse the URL and call the normal constructor
host, port, dbname = parse_db_url(url) # assumes a parse_db_url() helper
return cls(host, port, dbname)
@classmethod
def local_dev(cls):
return cls("localhost", 5432, "dev_db")
If your goal is to offer multiple ways to construct an object from different inputs, @classmethod is the right tool. If your goal is to change what happens during allocation itself, __new__ is the right tool. They solve different problems, and conflating them leads to unnecessarily complex class hierarchies.
The @classmethod decorator is part of Python's descriptor-based object model and was introduced with the descriptor work documented in PEP 252 during the Python 2.2 era. It is documented in the Python built-in functions reference.
Inheritance Is Where It Gets Interesting
This is the section that separates a working knowledge of @classmethod from a deep understanding of it. When a class method defined on a parent is called on a child class, cls refers to the child, not the parent. That behavior has concrete, non-trivial consequences for object creation.
class Animal:
sound = "..."
def __init__(self, name):
self.name = name
@classmethod
def create(cls, name):
# cls is whatever class this is called on
return cls(name)
def speak(self):
return f"{self.name} says {self.sound}"
class Dog(Animal):
sound = "woof"
class Cat(Animal):
sound = "meow"
dog = Dog.create("Rex")
cat = Cat.create("Luna")
print(type(dog)) #
print(type(cat)) #
print(dog.speak()) # Rex says woof
print(cat.speak()) # Luna says meow
When Dog.create("Rex") is called, Python passes Dog as cls. The call cls(name) therefore instantiates a Dog object. The factory method defined once on Animal produces the correct type automatically for every subclass.
Compare that to what would happen if the factory method used the parent class name directly:
class Animal:
@classmethod
def create_wrong(cls, name):
return Animal(name) # WRONG: always returns Animal, never a subclass
dog = Dog.create_wrong("Rex")
print(type(dog)) # -- not a Dog!
print(isinstance(dog, Dog)) # False
The official Python documentation confirms this behavior directly: if a class method is called for a derived class, the derived class object is passed as the implied first argument.
Hardcoding the parent class name in a factory method breaks polymorphism. Using cls(...) preserves it. This is the single most important thing to internalize about @classmethod. A static method used as a factory cannot exhibit this behavior — it receives no class reference at all, so it has no way to know which subclass is doing the calling.
The same logic applies when you need to read or set a class attribute that may be overridden in a subclass. Using cls.attribute always resolves to the attribute on the actual calling class, following normal attribute lookup through the MRO (Method Resolution Order), rather than hard-targeting the parent. This is worth understanding precisely: when you write cls.value inside a class method, Python walks the chain defined by cls.__mro__ — the tuple of classes from the calling class up through its parents to object — and returns the first match. That means a subclass can override a class attribute, and the inherited class method will automatically pick up the overridden value without any changes to the parent's code.
class Config:
DEBUG = False
DATABASE_URL = "sqlite:///default.db"
@classmethod
def show_config(cls):
print(f"Class: {cls.__name__}")
print(f"Debug: {cls.DEBUG}")
print(f"Database: {cls.DATABASE_URL}")
class ProductionConfig(Config):
DEBUG = False
DATABASE_URL = "postgresql://prod-server/appdb"
class DevelopmentConfig(Config):
DEBUG = True
DATABASE_URL = "sqlite:///dev.db"
ProductionConfig.show_config()
# Class: ProductionConfig
# Debug: False
# Database: postgresql://prod-server/appdb
DevelopmentConfig.show_config()
# Class: DevelopmentConfig
# Debug: True
# Database: sqlite:///dev.db
A single method defined once on Config produces the correct output for every subclass, because cls always refers to the class it was actually called on.
This one is more subtle. Consider the difference between @staticmethod and @classmethod in the context of inheritance.
class User:
def __init__(self, name):
self.name = name
@staticmethod
def create(name):
return User(name)
class Admin(User):
pass
obj = Admin.create("Alice")
print(type(obj).__name__)
What will the output be?
Answer:
User
Even though the method was called from Admin, the static method hardcodes the class name. This prevents subclass-aware construction. Replacing the method with a class method fixes the issue:
@classmethod
def create(cls, name):
return cls(name)
Now subclasses automatically construct their own type. If you predicted Admin, revisit the "Same Problem Solved Three Ways" section above — the distinction is the same mechanism at work.
Modifying Class-Level State
Beyond construction, @classmethod is the correct tool whenever you need to read or write state that belongs to the class as a whole rather than to any single instance. A common example is a shared counter or registry that tracks all instantiated objects.
class Session:
_active_sessions = []
_total_created = 0
def __init__(self, user_id):
self.user_id = user_id
type(self)._total_created += 1
type(self)._active_sessions.append(self)
def close(self):
type(self)._active_sessions.remove(self)
@classmethod
def active_count(cls):
return len(cls._active_sessions)
@classmethod
def total_created(cls):
return cls._total_created
@classmethod
def clear_all(cls):
cls._active_sessions.clear()
s1 = Session("user_001")
s2 = Session("user_002")
s3 = Session("user_003")
print(Session.active_count()) # 3
print(Session.total_created()) # 3
s2.close()
print(Session.active_count()) # 2
print(Session.total_created()) # still 3
Notice that active_count() and total_created() do not need any instance. They operate on the class itself. Declaring them as instance methods would require a caller to have an object on hand before querying class-wide information, which is semantically backward. Class methods express that intent precisely.
Also notice that __init__ and close() use type(self) rather than hardcoding Session. This keeps the example consistent with the subclass-safe principles taught throughout this article. If a subclass of Session were created, using type(self) ensures counters and session lists are modified on the correct class. One additional subtlety worth noting: mutable class attributes like _active_sessions = [] are shared across the entire inheritance chain unless each subclass explicitly defines its own list. Without that override, subclass instances would silently append to the parent's list, which can produce surprising cross-subclass behavior.
A @classmethod such as get_instance() can serve as a convenient singleton-style accessor, checking whether an instance already exists in a class variable and returning it rather than creating a new one. However, true singleton enforcement is a separate design problem and may be better handled with __new__, a metaclass, or module-level construction depending on the requirements.
Using @classmethod with Abstract Base Classes
When working with Python's abc module, you can combine @classmethod with @abstractmethod to require that all concrete subclasses provide a class-level factory. The official abc module documentation shows the correct stacking order: @classmethod goes on the outside, @abstractmethod on the inside.
from abc import ABC, abstractmethod
class Serializer(ABC):
@classmethod
@abstractmethod
def from_file(cls, filepath):
"""All subclasses must implement a file-based constructor."""
...
@abstractmethod
def serialize(self, data):
...
class JSONSerializer(Serializer):
@classmethod
def from_file(cls, filepath):
import json
with open(filepath) as f:
config = json.load(f)
instance = cls()
instance._config = config
return instance
def serialize(self, data):
import json
return json.dumps(data)
# Attempting to instantiate Serializer directly raises TypeError:
# TypeError: Can't instantiate abstract class Serializer
# with abstract methods from_file, serialize
This pattern enforces an interface contract at the class level, not just the instance level. It is widely used in frameworks where plugins or backends must expose a consistent construction API regardless of their internal implementation.
Common Mistakes and When Not to Use It
Understanding where @classmethod excels also means recognizing where it should not appear. Before getting into specific mistakes, it is worth correcting two misconceptions that cause confusion in the first place.
Misconception: @classmethod modifies the function. It does not. The original function is unchanged. What @classmethod modifies is the binding behavior — the rule Python uses to decide what gets passed as the first argument when the function is accessed as an attribute.
Misconception: @classmethod is just a convenience alternative to @staticmethod. They serve fundamentally different purposes. A class method supports polymorphic construction and class state management because it receives the class. A static method receives nothing and cannot participate in inheritance-aware behavior at all.
Trying to access instance attributes through cls. This is the most common error made by developers who are new to the decorator. The cls parameter is the class object, not an instance. Attempting to access an instance attribute through it raises an AttributeError at runtime.
class Product:
category = "general"
def __init__(self, name, price):
self.name = name # instance attribute
self.price = price # instance attribute
@classmethod
def broken_method(cls):
# WRONG: cls.name does not exist on the class
# It would only exist on an instance
print(cls.name) # AttributeError: type object 'Product'
# has no attribute 'name'
@classmethod
def correct_method(cls):
# RIGHT: cls.category is a class attribute
print(cls.category) # "general"
When a factory class method is inherited and a subclass changes __init__'s signature, the inherited factory may silently pass wrong arguments. Always override the factory method in the subclass or design the parent's factory to be flexible enough to handle the subclass's parameters.
Using @classmethod when a static method is sufficient. If your method does not need cls at all — it takes no class state and produces no instance — it should be a @staticmethod. Using @classmethod for utility functions that ignore cls misleads readers into thinking the method interacts with class-level state.
Forgetting super() in inherited class methods. When overriding a class method in a subclass, failing to call super().method() where appropriate breaks cooperative inheritance. This matters particularly in frameworks that use the class method to register or configure subclasses during class creation (a pattern used extensively in Django's model metaclass system, for example).
Overusing class methods as a substitute for module-level functions. A method that neither reads class attributes, modifies class state, nor constructs instances does not belong in a class at all. Python is not Java; there is no requirement to wrap every function in a class. If you find yourself writing class methods that use neither cls meaningfully nor self, a standalone function in a module is cleaner and more testable.
A Note on Performance
Advanced developers sometimes ask whether class methods carry a meaningful performance penalty compared to regular functions or static methods. In practice, the overhead is negligible. Calling a class method involves descriptor resolution and the creation of a bound method object, which adds a small fixed cost per call. Static methods skip the binding step entirely, and plain functions avoid descriptor lookup altogether. But the difference is measured in nanoseconds per call — far below the threshold that matters in any real application. Choosing between method types should always be a question of correctness and readability, not performance.
A Note on __init_subclass__
Python 3.6 introduced __init_subclass__, a hook defined on the parent class that fires whenever a child class is created. According to PEP 487, this method is implicitly converted to a class method by the runtime because there is no sensible interpretation for calling it as an instance method. It is one of the few places in the language where @classmethod behavior is applied automatically without an explicit decorator, and it illustrates just how fundamental the class-binding concept is to Python's inheritance machinery.
class PluginBase:
_registry = {}
def __init_subclass__(cls, plugin_name=None, **kwargs):
super().__init_subclass__(**kwargs)
if plugin_name:
PluginBase._registry[plugin_name] = cls
print(f"Registered plugin: {plugin_name} -> {cls.__name__}")
class AudioPlugin(PluginBase, plugin_name="audio"):
pass
class VideoPlugin(PluginBase, plugin_name="video"):
pass
print(PluginBase._registry)
# {'audio': ,
# 'video': }
This pattern — auto-registration of subclasses using class-level hooks — is an advanced but practical application of the same mechanism that powers @classmethod. Understanding one makes the other easier to reason about.
The One-Minute Mental Model
If you remember only one thing about @classmethod, remember this: Python methods differ only in how their first argument is bound.
# Python Method Binding
instance.method() → method(instance) # first arg = self
Class.classmethod() → method(Class) # first arg = cls
Class.staticmethod() → method() # no automatic first arg
The @classmethod decorator tells Python to pass the class object as the first argument instead of an instance. That single change in binding behavior is what enables polymorphic factories, alternative constructors, and class-level state management. Every pattern covered in this article follows from that one mechanism.
Key Takeaways
- @classmethod is a descriptor, not just syntax: It wraps a function so that Python's attribute lookup mechanism automatically binds the class (not the instance) as the first argument when the method is accessed.
- cls is the actual calling class: When a subclass calls an inherited class method,
clsis the subclass, not the parent. This is what makes factory methods polymorphic and inheritance-safe. - The primary use case is alternative constructors: Named class methods that return
cls(...)provide clean, named, flexible ways to instantiate objects beyond what a single__init__can express. - Use it for class-level state operations: Counters, registries, configuration accessors, and any logic that belongs to the class as a whole rather than to individual instances are appropriate class method candidates.
- It is not a substitute for @staticmethod or instance methods: If you need
self, write a normal method. If you need neitherclsnorself, write a@staticmethodor a module-level function. Misusing@classmethodfor logic that ignoresclsadds noise without benefit. - Stacking decorators has rules: When combining
@classmethodwith@abstractmethod,@classmethodmust be the outer decorator. The abc module documentation is explicit on this point.
Quick Decision Reference
When deciding which method type to use, work through this sequence: if the method needs to read or write instance state, write an instance method. If it needs to construct an instance or access class-level state, use @classmethod. If it needs neither instance nor class state but logically belongs in the class namespace, use @staticmethod. If it does not logically belong in the class at all, write a module-level function. And if the goal is to control how instances are allocated in memory (singletons, caching, returning a different type), override __new__ instead.
The broader lesson here is that Python's method types are not just organizational choices — each one expresses a specific relationship between a method and its context. Writing @classmethod is a declaration: "this method belongs to the class itself, and when called on a subclass, it should behave as if it belongs to that subclass." That precision is what makes well-structured Python code readable as a specification, not just as a set of instructions.
References
- Built-in Functions: classmethod — docs.python.org
- Python Descriptor HowTo Guide — docs.python.org
- abc module documentation — docs.python.org
- PEP 252: Making Types Look More Like Classes — peps.python.org
- PEP 487: Simpler customisation of class creation — peps.python.org
- classmethod() Built-in Reference — Real Python (updated February 2026)
Frequently Asked Questions About Python Class Methods
What is the difference between @classmethod and @staticmethod?
A class method receives the class object as its first argument (cls), while a static method receives no automatic argument. Class methods are commonly used for factory constructors or class-wide operations, whereas static methods behave like regular functions that happen to live inside a class namespace. If a method does not reference cls, it should probably be a static method or a module-level function.
When should you use @classmethod in Python?
Class methods are typically used when logic relates to the class itself rather than a specific instance. Common examples include alternative constructors (like from_csv() or from_json()), polymorphic factory methods that must produce the correct subclass type, and operations that read or modify class-level data such as counters, registries, or configuration values.
Can a classmethod create instances of subclasses?
Yes. Because the method receives the calling class through the cls parameter, calling a classmethod from a subclass will automatically create an instance of that subclass when the factory uses cls(...). This is the core advantage over @staticmethod factories, which would hardcode the base class name and break inheritance.
Can class methods access instance attributes?
No. Class methods do not receive an instance reference, so they cannot directly access instance attributes unless one is explicitly passed to them. They can only access class-level attributes through cls. Attempting to read an instance attribute through cls raises an AttributeError.