Классы, экземпляры и виды методов

Стартовый ООП-вопрос: класс против экземпляра, роль 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 — это просто функция-утилита внутри класса.
Проверьте себя
1. Что такое self в методе?
AИмя класса
BСсылка на текущий экземпляр
CГлобальная переменная
DКлючевое слово Python
2. Что получает первым аргументом classmethod?
Aself — экземпляр
Bcls — сам класс
Cничего
Dимя метода
3. Чем staticmethod отличается от обычного метода?
AОн быстрее
BНе получает ни self, ни cls — просто функция в namespace класса
CОн не может вызываться
DОн автоматически кеширует результат
Поддержать проект