Topics
You use @classmethod
when you need a method that operates on the class itself, rather than a specific instance of the class. The first argument to a class method is the class object, conventionally named cls
.
A primary use case for @classmethod
is defining alternative constructors for your class. Python only has one standard constructor, __init__
. If you need different ways to create instances based on varying inputs or logic, @classmethod
provides a way to do this with a common interface:
class Color:
def __init__(self, red, green, blue):
self.red = red
self.green = green
self.blue = blue
@classmethod
def from_hex(cls, hex_code):
# Convert hex string to RGB values
red = int(hex_code[1:3], 16)
green = int(hex_code[3:5], 16)
blue = int(hex_code[5:7], 16)
return cls(red, green, blue)
# Usage
color = Color.from_hex('#FF0000') # Creates a red color
Another practical use-case will be alongside mixins in python. Say I have a class A with some attributes and I need the ability to instantiate its object by reading/deserializing from JSON. We can create a JsonMixin
that implements the deserization classmethod as follows:
import json
class JsonMixin:
@classmethod
def from_json(cls, data):
kwargs = json.loads(data)
return cls(**kwargs) # Calls the class constructor (like MyClass(**kwargs))
# ... other methods ...
In this code, cls
refers to the class that inherits from JsonMixin
. The from_json
method uses this cls
object to create an instance of the subclass, providing a generic way to deserialize from JSON.
Another common way is to use it in conjuction with the factory design pattern:
class Vehicle:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"{self.__class__.__name__}({self.name})"
class Car(Vehicle):
pass
class Bike(Vehicle):
pass
class VehicleFactory:
_vehicle_types = {
"car": Car,
"bike": Bike,
}
@classmethod
def create_vehicle(cls, vehicle_type, name):
vehicle_class = cls._vehicle_types.get(vehicle_type.lower())
if vehicle_class:
return vehicle_class(name)
else:
raise ValueError("Unknown vehicle type")
# Usage
car = VehicleFactory.create_vehicle("car", "MySedan")
bike = VehicleFactory.create_vehicle("bike", "RoadKing")
print(car)
print(bike)
Here, though we can use @staticmethod
for our factory method create_vehicle
and use an if-else
construct inside to check the vehicle type and instantite the correct class accordingly, but @classmethod
is cleaner and allows us to refer the class var _vehicle_types
.