← Назад к вопросам

Чем отличается staticmethod от classmethod?

2.0 Middle🔥 131 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

staticmethod vs classmethod

Это два декоратора для определения методов в классе, но они работают по-разному. Различие в том, какой контекст они получают при вызове.

staticmethod

Определение: метод, который НЕ получает доступ к экземпляру (self) или классу (cls). Это обычная функция, но находится в пространстве имён класса.

class MathUtils:
    @staticmethod
    def add(a, b):
        # Нет self, нет cls
        return a + b
    
    @staticmethod
    def multiply(a, b):
        return a * b

# Вызов
print(MathUtils.add(5, 3))  # 8
print(MathUtils.multiply(4, 2))  # 8

# Работает и на экземпляре
calc = MathUtils()
print(calc.add(10, 5))  # 15

Характеристики:

  • Без доступа к состоянию: не может обращаться к self или cls
  • Утилита: просто логически связанная функция
  • Независимость: результат не зависит от состояния объекта или класса
  • Вызов: можно вызвать на классе или на экземпляре
  • Наследование: статический метод НЕ переопределяется (вызывается из класса, где определён)

classmethod

Определение: метод, который получает класс (cls) вместо экземпляра (self). Может работать с классовыми переменными и вызывать другие методы класса.

class Animal:
    species_count = 0  # Классовая переменная
    
    def __init__(self, name):
        self.name = name
        Animal.species_count += 1
    
    @classmethod
    def get_species_count(cls):
        # Получает cls вместо self
        return f"Всего животных: {cls.species_count}"
    
    @classmethod
    def from_string(cls, data):
        # Альтернативный конструктор
        name = data.split('|')[0]
        return cls(name)

# Вызов
dog = Animal("Шарик")
cat = Animal("Барсик")
print(Animal.get_species_count())  # Всего животных: 2

# Альтернативный конструктор
bird = Animal.from_string("Попугай|красный")
print(Animal.get_species_count())  # Всего животных: 3

Характеристики:

  • Доступ к классу: первый аргумент — cls (сам класс)
  • Изменение состояния класса: может менять классовые переменные
  • Вызов на любом классе: если переопределить в наследнике, вызовется нужный класс
  • Альтернативные конструкторы: популярное использование
  • Наследование: правильно работает с наследованием

Сравнение

class Dog:
    breed = "Unknown"
    
    def __init__(self, name):
        self.name = name
    
    def instance_method(self):
        # Работает с экземпляром
        return f"Это собака {self.name}"
    
    @staticmethod
    def is_dog():
        # Просто функция
        return True
    
    @classmethod
    def get_breed(cls):
        # Работает с классом
        return f"Порода: {cls.breed}"
    
    @classmethod
    def change_breed(cls, new_breed):
        # Может менять классовые данные
        cls.breed = new_breed

# Примеры вызова
dog = Dog("Рекс")
print(dog.instance_method())      # Это собака Рекс
print(Dog.is_dog())               # True
print(Dog.get_breed())            # Порода: Unknown

Dog.change_breed("Овчарка")
print(Dog.get_breed())            # Порода: Овчарка

Наследование (важное отличие!)

class Animal:
    name = "Animal"
    
    @staticmethod
    def static_info():
        return "Static info"
    
    @classmethod
    def class_info(cls):
        return f"Class: {cls.name}"

class Dog(Animal):
    name = "Dog"

class Cat(Animal):
    name = "Cat"

# staticmethod НЕ учитывает переопределение
print(Dog.static_info())   # Static info (вызывается из Animal)
print(Cat.static_info())   # Static info (вызывается из Animal)

# classmethod учитывает переопределение
print(Dog.class_info())    # Class: Dog (используется Dog.name)
print(Cat.class_info())    # Class: Cat (используется Cat.name)

Таблица сравнения

Параметрinstance_methodstaticmethodclassmethod
Первый аргументselfнетcls
Доступ к состоянию экземпляраДаНетНет
Доступ к состоянию классаДа (через cls)НетДа
Вызов на классеНет (ошибка)ДаДа
Вызов на экземпляреДаДаДа
НаследованиеПереопределяетсяНЕ переопределяетсяПереопределяется
ИспользованиеОсновной методУтилитыАльт. конструкторы

Когда использовать что

instance_method (обычный метод):

  • Работа с данными экземпляра
  • Изменение состояния объекта
  • Большинство методов класса
class User:
    def __init__(self, name):
        self.name = name
    
    def greet(self):
        return f"Привет, я {self.name}"

@staticmethod:

  • Вспомогательные функции
  • Логика не связана с объектом или классом
  • Группировка похожих утилит
class Validator:
    @staticmethod
    def is_valid_email(email):
        return "@" in email
    
    @staticmethod
    def is_valid_phone(phone):
        return len(phone) >= 10

@classmethod:

  • Альтернативные конструкторы (factory pattern)
  • Работа с классовыми данными
  • Правильное наследование
class Date:
    def __init__(self, day, month, year):
        self.day = day
        self.month = month
        self.year = year
    
    @classmethod
    def from_string(cls, date_string):
        # Альтернативный конструктор
        day, month, year = map(int, date_string.split('.'))
        return cls(day, month, year)
    
    @classmethod
    def today(cls):
        # Ещё один альтернативный конструктор
        import datetime
        d = datetime.date.today()
        return cls(d.day, d.month, d.year)

date1 = Date(25, 12, 2024)
date2 = Date.from_string("25.12.2024")
date3 = Date.today()

Вывод

  • instance_method: основной выбор, работает с объектом
  • staticmethod: когда функция логически принадлежит классу, но не нужен доступ к self или cls
  • classmethod: когда нужен доступ к классу, особенно для наследования и альтернативных конструкторов

В реальном коде classmethod встречается чаще, чем staticmethod. Это один из важных паттернов в Python, который надо хорошо понимать на собеседовании.