В чем разница между @staticmethod и @classmethod в Python?

«В чем разница между @staticmethod и @classmethod в Python?» — вопрос из категории Скриптинг и автоматизация, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Оба декоратора определяют методы, которые вызываются от имени класса, а не экземпляра, но имеют ключевые отличия:

  • @classmethod:

    • Первым аргументом всегда принимает ссылку на сам класс (по соглашению cls).
    • Имеет доступ к атрибутам и методам класса и может их изменять.
    • Часто используется как фабричный метод для альтернативных конструкторов.
  • @staticmethod:

    • Не получает неявных ссылок (self или cls). Это обычная функция, помещенная в пространство имен класса для логической группировки.
    • Не имеет доступа к состоянию класса или экземпляра.
    • Используется для утилитарных функций, связанных с предметной областью класса.

Пример из практики DevOps (работа с конфигурацией):

class AppConfig:
    _env = 'production'  # Классовая переменная

    def __init__(self, config_path):
        self.path = config_path

    @classmethod
    def from_environment(cls):
        """Фабричный метод: создает конфиг на основе переменных окружения."""
        env = os.getenv('APP_ENV', cls._env)
        config_path = f'/etc/app/config.{env}.yaml'
        return cls(config_path)  # Возвращает экземпляр этого же класса

    @staticmethod
    def validate_yaml(path):
        """Статический метод: утилита для проверки YAML."""
        try:
            with open(path) as f:
                yaml.safe_load(f)
            return True
        except yaml.YAMLError:
            return False

# Использование
config = AppConfig.from_environment()  # Вызов classmethod
is_valid = AppConfig.validate_yaml('/tmp/test.yaml')  # Вызов staticmethod