Ответ
Основное различие заключается в том, к чему привязан метод и какой первый аргумент он принимает.
- Обычный метод (instance method): Привязан к экземпляру класса. Первым аргументом неявно принимает сам экземпляр, который по соглашению называется
self
. - Метод класса (
@classmethod
): Привязан к классу. Первым аргументом неявно принимает сам класс, который по соглашению называетсяcls
.
Сравнение в коде:
class User:
# Атрибут класса
total_users = 0
def __init__(self, name):
# Атрибут экземпляра
self.name = name
User.total_users += 1
# Обычный метод, работает с данными экземпляра (self.name)
def say_hello(self):
print(f"Hello, my name is {self.name}")
# Метод класса, работает с данными класса (cls.total_users)
@classmethod
def get_total_users(cls):
print(f"Total users: {cls.total_users}")
# Создаем экземпляры
user1 = User("Alice")
user2 = User("Bob")
# Вызов обычного метода через экземпляр
user1.say_hello() # Output: Hello, my name is Alice
# Вызов метода класса можно делать как от класса, так и от экземпляра
User.get_total_users() # Output: Total users: 2
user2.get_total_users() # Output: Total users: 2
Когда использовать @classmethod
?
Основное применение — фабричные методы, которые создают экземпляры класса альтернативными способами. Это позволяет инкапсулировать логику создания объекта.
Пример фабричного метода:
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def from_birth_year(cls, name, birth_year):
# cls - это класс Person
# Метод вычисляет возраст и создает экземпляр
current_year = date.today().year
age = current_year - birth_year
return cls(name, age)
# Создание объекта стандартным способом
person1 = Person("John", 30)
# Создание объекта с помощью фабричного метода
person2 = Person.from_birth_year("Jane", 1995)
print(person2.age) # Выведет возраст, рассчитанный на основе года рождения