В чем разница между методом класса (classmethod) и статическим методом (staticmethod) в ООП?

«В чем разница между методом класса (classmethod) и статическим методом (staticmethod) в ООП?» — вопрос из категории ООП, который задают на 33% собеседований Data Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Основное различие заключается в том, какой контекст (объект) передается методу в качестве первого неявного аргумента, и, как следствие, к каким данным метод имеет доступ.

Аспект Метод класса (@classmethod) Статический метод (@staticmethod)
Первый аргумент cls — ссылка на сам класс. Нет неявного аргумента. Принимает только явно переданные.
Доступ к: Атрибутам и другим методам класса (через cls). Только к переданным аргументам. Не имеет доступа ни к self, ни к cls.
Может изменять: Состояние класса (например, классовые переменные). Ничего, если не передано явно.
Основное назначение Альтернативные конструкторы, методы, работающие с классом как целым. Вспомогательные функции, логически связанные с классом, но не требующие доступа к его состоянию.

Практический пример на Python:

class Order:
    tax_rate = 0.20  # Ставка НДС — атрибут класса

    def __init__(self, amount):
        self.amount = amount

    @classmethod
    def from_string(cls, order_str):
        # Альтернативный конструктор: создает объект из строки
        amount = float(order_str.replace('USD', ''))
        return cls(amount)  # Вызывает __init__

    @classmethod
    def update_tax_rate(cls, new_rate):
        # Меняет атрибут, общий для всех экземпляров
        cls.tax_rate = new_rate

    @staticmethod
    def format_currency(value):
        # Вспомогательная функция, не зависящая от класса или экземпляра
        return f"{value:.2f} USD"

    def calculate_total(self):
        return self.amount * (1 + self.tax_rate)

# Использование:
order1 = Order.from_string("100.50 USD")  # Создание через classmethod
print(order1.calculate_total())  # 120.60

Order.update_tax_rate(0.18)  # Меняем ставку для всех заказов
print(Order.format_currency(150))  # "150.00 USD" - вызов staticmethod

Таким образом, classmethod используется, когда логика метода привязана к классу, а staticmethod — когда это просто удобное место для размещения функции, связанной с предметной областью класса.