← Назад к вопросам
Чем отличается 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_method | staticmethod | classmethod |
|---|---|---|---|
| Первый аргумент | 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, который надо хорошо понимать на собеседовании.