The simplest way to understand the difference is to consider them in different categories. The @staticmethod decorator is in that context just a function wrapped by a class body. It could have lived outside the class anyway as it doesn't refer to any of its specific properties. The @classmethod decorator is different as it lets you call the function on a class. Probably one of the most obvious use cases is the factory pattern, hence an alternative instance initialization, as presented below:
from __future__ import annotations
class Letter:
def __init__(self, letter: str):
self.__letter = letter
@property
def letter(self) -> str:
return self.__letter
@classmethod
def from_int(cls, letter_int: int) -> Letter:
return cls(chr(letter_int))
letter_string = Letter('A')
assert(letter_string.letter == 'A')
letter_int = Letter.from_int(112)
assert(letter_int.letter == 'p')
Besides, the @classmethod can be also overridden while the @staticmethod can't, since it's attached statically to a class:
class UpperCaseLetter(Letter):
@classmethod
def from_int(cls, letter_int: int) -> Letter:
return cls(chr(letter_int).upper())
letter_string = UpperCaseLetter('a')
assert (letter_string.letter == 'a')
letter_int = UpperCaseLetter.from_int(112)
assert (letter_int.letter == 'P')