Ответ
Основное различие заключается в том, к чему привязан метод и какой первый аргумент он принимает.
- Обычный метод (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) # Выведет возраст, рассчитанный на основе года рождения Ответ 18+ 🔞
А, слушай, смотри, тут один нюанс, который мозги выносит начинающим. Разница между обычным методом и этим самым @classmethod. Суть проще, чем кажется, если не загоняться.
Представь себе завод. Класс — это чертёж завода и само здание с вывеской. Экземпляр — это конкретная тачка, которая с конвейера съехала.
- Обычный метод — это инструкция для водителя тачки. Первым делом ему говорят: «Смотри на свою тачку (
self)». «Включи фары», «Дай гудок» — всё это про конкретный экземпляр. - Метод класса (
@classmethod) — это инструкция для директора завода или охранника на проходной. Первым делом ему говорят: «Смотри на сам завод (cls)». «Сколько всего тачек выпустили?», «Поменяй вывеску на здании» — это про весь класс в целом.
Вот, смотри, наглядненько:
class User:
# Это как общий счётчик на проходной завода
total_users = 0
def __init__(self, name):
# Каждая новая тачка (экземпляр) — счётчик тикает
self.name = name
User.total_users += 1
# Обычный метод. Водитель (self) представляется.
def say_hello(self):
print(f"Hello, my name is {self.name}")
# Метод класса. Охранник (cls) докладывает статистику по заводу.
@classmethod
def get_total_users(cls):
print(f"Total users: {cls.total_users}")
# Сошлифовали две тачки с конвейера
user1 = User("Alice")
user2 = User("Bob")
# Водитель user1 гудкает
user1.say_hello() # Вывод: Hello, my name is Alice
# Спросим у завода (класса) статистику
User.get_total_users() # Вывод: Total users: 2
# Или спросим у тачки user2, но она перенаправит на завод
user2.get_total_users() # Вывод: Total users: 2
А зачем этот @classmethod нахуй вообще нужен?
Основная фишка — фабричные методы. Ну то есть альтернативные способы слепить объект, когда стандартный __init__ неудобен. Чтоб логику создания не выносить в какие-то внешние функции, а держать её при классе, где ей и место.
Пример, чтобы въехать:
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) # Выведет актуальный возраст, всё посчитано внутри.
Вот и вся философия. Не усложняй, блядь. self — про штуку. cls — про чертёж, по которому все штуки делаются. А фабричные методы — это просто удобные цеха при этом заводе.