Приведи примеры использования staticmethod и classmethod в Python
Что проверяют
Понимаете ли, что cls это не «класс, в котором написан метод», а тот класс, через который метод вызвали. Отсюда растёт единственная по-настоящему важная разница: classmethod переживает наследование, staticmethod нет.
Как отвечать
classmethod первым аргументом получает класс, staticmethod не получает ничего: это обычная функция, которая живёт в пространстве имён класса.
classmethod берут для альтернативных конструкторов:
class Money:
def __init__(self, cents):
self.cents = cents
@classmethod
def from_rubles(cls, rubles):
return cls(round(rubles * 100)) # cls, а не Money
class Bonus(Money):
pass
Bonus.from_rubles(10) # вернёт Bonus, а не MoneyВ стандартной библиотеке так устроены dict.fromkeys, datetime.now, int.from_bytes. Второе применение: методы, работающие с состоянием самого класса, например реестр подклассов.
staticmethod берут, когда функция логически принадлежит классу, но ни экземпляр, ни класс ей не нужны: разбор строки в поле, проверка формата, короткий расчёт рядом с местом применения. Пример из библиотеки, str.maketrans.
Если функция не нужна ни как часть интерфейса класса, ни наследникам, честнее вынести её на уровень модуля: в Python нет требования заворачивать всё в классы.
Где спотыкаются
Делают альтернативный конструктор через staticmethod и пишут внутри имя класса. Наследник получит объект родителя, и ошибка всплывёт далеко от строки, где написана.
Второе: забывают сам декоратор. Метод становится обычным, первым аргументом приезжает экземпляр, вызов от класса падает с жалобой на число аргументов, а вызов от экземпляра тихо работает не так, как задумано.
Третье: меняют атрибут класса через cls и удивляются результату. Строка cls.counter += 1, вызванная у наследника, читает значение родителя, а записывает новое поле в наследника, и общий счётчик разъезжается на два. Если состояние действительно общее, обращаться надо к конкретному классу.