Understanding Python classmethod()
In Python, a class method is a special type of method that is bound to the class and not its instance. You create a class method using the @classmethod decorator. The most important feature of a Python class method() is that it receives the class itself as the first argument, conventionally named cls. This allows the method to access and modify class-level data or perform other operations relevant to the class as a whole. They can’t modify the object instance state.
Syntax of Python classmethod
()
classmethod
()
class MyClass:
@classmethod
def my_class_method(cls, arg1, arg2):
# Method body
Explanation
class MyClass:
: Defines a class namedMyClass
.@classmethod
: Decorator that marks the following method as a class method.def my_class_method(cls, arg1, arg2):
: Defines the class method.cls
: First argument to the class method, representing the class itself. It is similar toself
for instance methods, butcls
refers to class.arg1, arg2
: Regular arguments that the class method can accept.# Method body
: This is where you write the code that the class method will execute.
Example of Python classmethod
()
classmethod
()
class Employee:
num_of_employees = 0
def __init__(self, name):
self.name = name
Employee.num_of_employees += 1
@classmethod
def get_count(cls):
return cls.num_of_employees
print(Employee.get_count())
emp1 = Employee("Alice")
print(Employee.get_count())
Explanation
class Employee:
: Defines a class namedEmployee
.num_of_employees = 0
: Initializes a class-level variable to keep track of the number of employees.def __init__(self, name):
: This is the constructor for the class.self.name = name
: Initializes an instance variablename
.Employee.num_of_employees += 1
: Increments thenum_of_employees
counter each time anEmployee
object is created.@classmethod
: Decorator marks theget_count
method as a class method.def get_count(cls):
: Defines the class methodget_count
, which takes the class itself as the first argument (cls
).return cls.num_of_employees
: Returns the current value of the class variablenum_of_employees
.print(Employee.get_count())
: Calls the class methodget_count
directly on theEmployee
class and prints the result.emp1 = Employee("Alice")
: Creates an instance of theEmployee
class.print(Employee.get_count())
: Again callsget_count
after an employee object has been created.
Output
0
1
classmethod()
Parameters
A class method, created using the @classmethod
decorator, always takes the class itself as its first parameter. This parameter is conventionally named cls
, but you can technically use any valid variable name (though it’s strongly recommended to stick with cls
for readability). After the cls
parameter, a Python classmethod can accept any number of other arguments, just like a regular method. These additional parameters can be used to pass data to the class method.
Syntax
class MyClass:
@classmethod
def my_method(cls, param1, param2, ...):
# Method body
Example
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@classmethod
def square(cls, side):
return cls(side, side)
my_square = Rectangle.square(5)
print(my_square.width)
print(my_square.height)
Explanation
class Rectangle:
: Defines a class namedRectangle
.def __init__(self, width, height):
: Constructor forRectangle
.self.width = width
: Initializes thewidth
attribute of theRectangle
instance.self.height = height
: Initializes theheight
attribute of theRectangle
instance.@classmethod
: Decorator marks thesquare
method as a class method.def square(cls, side):
: Defines the class methodsquare
, which takes the class (cls
) andside
as parameters.return cls(side, side)
: Creates and returns a newRectangle
object with equalwidth
andheight
.my_square = Rectangle.square(5)
: Calls the class methodsquare
on theRectangle
class to create a square with side length 5.print(my_square.width)
: Prints thewidth
of the created square.print(my_square.height)
: Prints theheight
of the created square.
Output
5
5
classmethod()
Return Value
Python classmethod() can return any value, such as a regular function or method. What the method returns depends on what you’ve programmed it to do. It could return a new class instance, a calculated value, a string, or even None if you don’t explicitly return anything. The important thing to remember is that the return value is associated with the class, not a specific instance of the class because class methods operate at the class level.
Example
class MathUtils:
@classmethod
def add(cls, x, y):
return x + y
result = MathUtils.add(10, 20)
print(result)
Explanation
class MathUtils:
: Defines a class namedMathUtils
.@classmethod
: Decorator marksadd
as a class method.def add(cls, x, y):
: Defines the class methodadd
.return x + y
: Returns the sum ofx
andy
.result = MathUtils.add(10, 20)
: Calls theadd
method on theMathUtils
class and stores the result inresult
.print(result)
: Prints the value ofresult
, which is 30.
Output
30
Class Method vs Static Method
In Python, both class and static methods are associated with a class but work differently. A class method receives the class itself as the first argument (conventionally named cls), while a static method doesn’t receive any special first argument. This means a class method can access and modify class-level data while a static method can’t. Static methods are essentially like regular functions that happen to be defined inside a class and don’t have access to cls or self. They are used to group logically related functions inside a class for better organization.
Syntax
class MyClass:
@classmethod
def my_class_method(cls, ...):
# Class method body
@staticmethod
def my_static_method(...):
# Static method body
Explanation
class MyClass:
: Defines a class namedMyClass
.@classmethod
: Decorator marksmy_class_method
as a class method.def my_class_method(cls, ...):
: Defines the class method, which takes the classcls
as the first argument.# Class method body
: This is where you write the code for the class method.@staticmethod
: Decorator marksmy_static_method
as a static method.def my_static_method(...):
: Defines the static method, which does not takecls
orself
as an argument.# Static method body
: This is where you write the code for the static method.
Example
class MyClass:
class_var = "I am a class variable"
@classmethod
def class_method(cls):
print(f"Class method called for {cls.__name__}")
print(cls.class_var)
@staticmethod
def static_method():
print("Static method called")
MyClass.class_method()
MyClass.static_method()
Explanation
class MyClass:
: Defines a class namedMyClass
.class_var = "I am a class variable"
: Initializes a class-level variable.@classmethod
: Marksclass_method
as a class method.def class_method(cls):
: Defines the class methodclass_method
.print(f"Class method called for {cls.__name__}")
: Prints the name of the class.print(cls.class_var)
: Accesses and prints the class variableclass_var
.@staticmethod
: Marksstatic_method
as a static method.def static_method():
: Defines the static methodstatic_method
.print("Static method called")
: Prints a message.MyClass.class_method()
: Calls the class method onMyClass
.MyClass.static_method()
: Calls the static method onMyClass
.
Output
Class method called for MyClass
I am a class variable
Static method called
Create a Simple classmethod without Python classmethod()
Usually, you’d use the @classmethod decorator to create a class method. However, to avoid the decorator, you can use the classmethod() function to achieve a similar result. You define a regular function and then pass it to classmethod() function. This approach is less common and readable, but it demonstrates that decorators are essentially “syntactic sugar” that makes your code cleaner and more intuitive. In this case, you must pass the function name to classmethod() function.
Syntax
class MyClass:
def my_method(cls, ...):
# Method body
my_method = classmethod(my_method)
Explanation
class MyClass:
: Defines a class namedMyClass
.def my_method(cls, ...):
: Defines a regular method that you intend to make into a class method.# Method body
: This is where you write the code for the method.my_method = classmethod(my_method)
: Convertsmy_method
into a class method using theclassmethod()
function.
Example
class Dog:
species = "Canis familiaris"
def describe(cls):
print(f"Dogs belong to the species {cls.species}")
Dog.describe = classmethod(Dog.describe)
Dog.describe()
Explanation
class Dog:
: Defines a class namedDog
.species = "Canis familiaris"
: Initializes a class-level variablespecies
.def describe(cls):
: Defines a methoddescribe
that will be converted into a class method.print(f"Dogs belong to the species {cls.species}")
: Prints the species of the dog, accessing the class variablespecies
.Dog.describe = classmethod(Dog.describe)
: Converts thedescribe
method into a class method usingclassmethod()
.Dog.describe()
: Calls the class methoddescribe
on theDog
class.
Output
Dogs belong to the species Canis familiaris
How the Class Method Works for the Inheritance?
In Python, class methods participate in inheritance, meaning they can be called subclasses and overridden in subclasses. When a class method is called on a subclass, the subclass itself is passed as the cls argument. This allows class methods for polymorphic behavior at the class level. If a subclass overrides a class method, the subclass’s version of the method will be called, but it will still receive the subclass as its first argument.
Syntax
class Parent:
@classmethod
def my_method(cls):
# Parent class method body
class Child(Parent):
@classmethod
def my_method(cls):
# Child class method body
Explanation
class Parent:
: Defines a parent class namedParent
.@classmethod
: Decorator marksmy_method
in the parent class as a class method.def my_method(cls):
: Defines the parent’s class method, which takescls
(the class) as its first argument.# Parent class method body
: Code for the parent’s class method goes here.class Child(Parent):
: Defines a child class namedChild
that inherits fromParent
.@classmethod
: Decorator marksmy_method
in the child class as a class method.def my_method(cls):
: Defines the child’s class method, which also takescls
(the class) as its first argument.# Child class method body
: The code for the child’s class method goes here.
Example
class Animal:
@classmethod
def make_sound(cls):
print(f"A generic {cls.__name__} sound")
class Cat(Animal):
@classmethod
def make_sound(cls):
print(f"Meow! I'm a {cls.__name__}")
Animal.make_sound()
Cat.make_sound()
Explanation
class Animal:
: Defines a parent class namedAnimal
.@classmethod
: Decorator marksmake_sound
inAnimal
as a class method.def make_sound(cls):
: Defines the class methodmake_sound
forAnimal
.print(f"A generic {cls.__name__} sound")
: Prints a generic sound message, usingcls.__name__
to refer to the class name.class Cat(Animal):
: Defines aCat
class that inherits fromAnimal
.@classmethod
: Decorator marksmake_sound
inCat
as a class method.def make_sound(cls):
: Defines the class methodmake_sound
forCat
, overriding the parent’s method.print(f"Meow! I'm a {cls.__name__}")
: Prints a specific sound message forCat
.Animal.make_sound()
: Calls the class methodmake_sound
on theAnimal
class.Cat.make_sound()
: Calls the class methodmake_sound
on theCat
class.
Output
A generic Animal sound
Meow! I’m a Cat
Factory Method Using Class Method
A factory method is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. In Python, you can implement a factory method using a Python class method. The class method acts as a factory that can create and return class instances. This is especially useful when the object creation logic is complex, or you want to return different subclasses based on different inputs.
Syntax
class MyClass:
def __init__(self, ...):
# Constructor body
@classmethod
def create_object(cls, ...):
# Logic to create and return an instance of MyClass
return cls(...)
Explanation
class MyClass:
: Defines a class namedMyClass
.def __init__(self, ...):
: Constructor forMyClass
, initializing new instances.# Constructor body
: Code to initialize the object’s attributes goes here.@classmethod
: Decorator markscreate_object
as a class method, making it a factory method.def create_object(cls, ...):
: Defines the factory method, which takescls
(the class) as its first argument.# Logic to create and return an instance of MyClass
: This is where you write the code to set up the new object.return cls(...)
: Creates and returns a new instance ofMyClass
(or a subclass), usingcls
to refer to the class.
Example
class DataProcessor:
def __init__(self, data):
self.data = data
@classmethod
def from_string(cls, data_string, delimiter):
data = data_string.split(delimiter)
return cls(data)
processor = DataProcessor.from_string("apple,banana,cherry", ",")
print(processor.data)
Explanation
class DataProcessor:
: Defines a class namedDataProcessor
.def __init__(self, data):
: Constructor forDataProcessor
, takingdata
as an argument.self.data = data
: Initializes thedata
attribute of theDataProcessor
instance.@classmethod
: Decorator marksfrom_string
as a class method and a factory method.def from_string(cls, data_string, delimiter):
: Defines the factory methodfrom_string
.data = data_string.split(delimiter)
: Splits the input string into a list using the provided delimiter.return cls(data)
: Creates and returns a newDataProcessor
instance, passing the processeddata
to the constructor.processor = DataProcessor.from_string("apple,banana,cherry", ",")
: Calls thefrom_string
factory method to create aDataProcessor
object.print(processor.data)
: Prints thedata
attribute of theDataProcessor
object.
Output
[‘apple’, ‘banana’, ‘cherry’]
Accessing Class-Level Data using Class Method
Class methods are often used to access or modify class-level data, which is shared across all class instances. Since a Python classmethod() receives the class itself as its first argument (conventionally named cls), you can use cls to reference class-level variables and other class attributes. This allows you to interact with data associated with the class rather than specific instances.
Syntax
class MyClass:
class_variable = ...
@classmethod
def my_method(cls, ...):
# Access or modify cls.class_variable
Explanation
class MyClass:
: Defines a class namedMyClass
.class_variable = ...
: Initializes a class-level variable.@classmethod
: Decorator marksmy_method
as a class method.def my_method(cls, ...):
: Defines the class methodmy_method
, withcls
as the first argument.# Access or modify cls.class_variable
: Inside the method, you can usecls.class_variable
to access or change the class-level data.
Example
class Counter:
count = 0
@classmethod
def increment(cls):
cls.count += 1
@classmethod
def get_count(cls):
return cls.count
Counter.increment()
Counter.increment()
print(Counter.get_count())
Explanation
class Counter:
: Defines a class namedCounter
.count = 0
: Initializes a class-level variablecount
to 0.@classmethod
: Decorator marksincrement
as a class method.def increment(cls):
: Defines the class methodincrement
.cls.count += 1
: Increments the class-level variablecount
.@classmethod
: Decorator marksget_count
as a class method.def get_count(cls):
: Defines the class methodget_count
.return cls.count
: Returns the current value ofcount
.Counter.increment()
: Calls theincrement
method to increasecount
.Counter.increment()
: Callsincrement
again.print(Counter.get_count())
: Callsget_count
to retrieve and print the current count.
Output
2
Conclusion
Python classmethod() provides a way to define methods that operate on the class itself rather than on class instances. Using the @classmethod decorator, you can create methods that receive the class as their first argument, conventionally named cls. Class methods are useful for factory methods, accessing or modifying class-level data, and interacting with subclasses during inheritance. They offer a powerful tool for organizing and structuring your code in an object-oriented way, especially when dealing with operations that concern the class as a whole rather than specific instances. Understanding when and how to use Python classmethod is an important aspect of mastering Python’s object-oriented programming features.