Классы, экземпляры и виды методов
Стартовый ООП-вопрос: класс против экземпляра, роль self, где живут атрибуты и какие бывают методы.
Класс — шаблон объектов, экземпляр — конкретный объект по шаблону,
self— ссылка на текущий экземпляр.
self и атрибуты экземпляра
Чёткий ответ. self — первый параметр методов, через который метод обращается к данным конкретного экземпляра. Вызов obj.method() на самом деле выполняет Class.method(obj).
class Dog:
def __init__(self, name):
self.name = name # атрибут экземпляра
def bark(self):
return f"{self.name} говорит: Гав!"
rex = Dog("Рекс")
bella = Dog("Белла")
print(rex.bark())
print(bella.bark())
Вывод:
Рекс говорит: Гав! Белла говорит: Гав!
Атрибут класса против атрибута экземпляра
Атрибут класса общий для всех экземпляров; атрибут экземпляра свой у каждого. Осторожно с изменяемым атрибутом класса (общий список) — изменение увидят все объекты, поэтому mutable-данные создавайте в __init__ через self.items = [].
class Counter:
total = 0 # атрибут класса — общий
def __init__(self):
Counter.total += 1 # увеличиваем общий счётчик
a = Counter()
b = Counter()
c = Counter()
print("всего создано:", Counter.total)
Вывод:
всего создано: 3
Три вида методов: чем отличаются?
Чёткий ответ. Обычный метод работает с данными экземпляра через self. @classmethod работает с классом через cls — удобно для альтернативных конструкторов. @staticmethod — просто функция в пространстве имён класса, ей не нужны ни экземпляр, ни класс.
class Pizza:
count = 0
def __init__(self, size):
self.size = size
Pizza.count += 1
def describe(self): # метод экземпляра
return f"пицца размера {self.size}"
@classmethod
def total(cls): # метод класса
return cls.count
@staticmethod
def is_valid_size(size): # статический метод
return size in ("S", "M", "L")
p = Pizza("M")
print(p.describe())
print("всего пицц:", Pizza.total())
print("размер XL валиден:", Pizza.is_valid_size("XL"))
Вывод:
пицца размера M всего пицц: 1 размер XL валиден: False
classmethod как альтернативный конструктор
Самое полезное применение @classmethod — создавать объекты разными способами. cls позволяет это работать и для подклассов.
class Date:
def __init__(self, year, month, day):
self.year, self.month, self.day = year, month, day
@classmethod
def from_string(cls, s): # альтернативный конструктор
year, month, day = map(int, s.split("-"))
return cls(year, month, day)
def __repr__(self):
return f"Date({self.year}, {self.month}, {self.day})"
d = Date.from_string("2026-06-14")
print(d)
Вывод:
Date(2026, 6, 14)
Когда что выбирать
| Нужны данные экземпляра | метод экземпляра (self) |
| Нужен класс, альтернативный конструктор | @classmethod (cls) |
| Просто связанная утилита, без доступа к объекту | @staticmethod |
Итог
- Метод экземпляра получает
selfи работает с конкретным объектом. @classmethodполучаетcls— удобен для альтернативных конструкторов.@staticmethodне получает ниself, ниcls— это просто функция-утилита внутри класса.