Урок 05 из 12 · 2 минуты чтения

ООП в Python — классы, свойства, наследование и dataclass

self и __init__, магические методы, property, staticmethod и classmethod, MRO и super, dataclass против namedtuple и Pydantic, ABC и Protocol, метаклассы.

Класс и экземпляр

class Account:
    currency = "RUB"              # атрибут класса — общий для всех

    def __init__(self, owner):
        self.owner = owner        # атрибут экземпляра
        self.balance = 0

self — ссылка на текущий экземпляр, Python передаёт её первым аргументом. __init__ не создаёт объект, а заполняет уже созданный — создаёт __new__. Изменяемый атрибут класса (items = []) общий для всех экземпляров — частая ошибка.

Магические методы

Методы вида __имя__ подключают объект к операциям языка: __len__ к len(), __iter__ к for, __eq__ к ==, __enter__ и __exit__ к with, __call__ к вызову.

  • __repr__ — однозначное представление для разработчика: Account(owner='Анна');
  • __str__ — читаемое для человека. print берёт __str__, а если его нет — __repr__. Поэтому __repr__ пишут всегда.

property

@property превращает метод в атрибут: снаружи obj.area, внутри — вычисление или проверка.

class Rect:
    def __init__(self, w, h):
        self.w, self.h = w, h

    @property
    def area(self):
        return self.w * self.h

@x.setter добавляет проверку при присваивании. В Python не пишут get_x() и set_x() заранее: начинают с обычного атрибута и заменяют его на property, когда понадобится, — вызывающий код не меняется.

staticmethod и classmethod

@classmethod получает класс (cls) — это способ писать альтернативные конструкторы: User.from_json(data). При наследовании cls будет подклассом, и создастся объект нужного типа. @staticmethod не получает ничего — это обычная функция, логически относящаяся к классу.

Наследование и MRO

MRO — порядок поиска метода по иерархии, его строит алгоритм C3: Class.__mro__. super() вызывает следующий класс в MRO, а не просто родителя — при множественном наследовании это разные вещи. В «ромбе» общий предок встречается в MRO один раз, и каждый класс вызывается ровно однажды, если все используют super().

dataclass, namedtuple и Pydantic

Что даётКогда
@dataclass__init__, __repr__, __eq__ по полям; без проверки типоввнутренние структуры
namedtupleнеизменяемый кортеж с именами полейлёгкие записи, распаковка
Pydanticпроверка и преобразование данных, JSONвнешние данные: API, конфиги
from dataclasses import dataclass, field

@dataclass(frozen=True, slots=True)
class Point:
    x: float
    y: float
    tags: list[str] = field(default_factory=list)

frozen=True — неизменяемость и согласованный хеш, slots=True — экономия памяти. Изменяемое значение по умолчанию — только через default_factory.

ABC и Protocol

ABC — номинальная типизация: класс явно наследует абстрактный, и пока не реализованы все @abstractmethod, экземпляр не создать. Protocol — структурная: подходит любой класс с нужными методами, без наследования, а проверяет это mypy или pyright. Protocol удобен для чужих классов, которые нельзя изменить; ABC может нести общую реализацию.

Метаклассы

Класс — тоже объект, метакласс — класс класса, по умолчанию type. Метаклассы используют ABCMeta, Enum, модели Django и SQLAlchemy. В своём коде регистрацию и проверку подклассов почти всегда проще сделать через __init_subclass__ или декоратор класса. «Если вы сомневаетесь, нужен ли метакласс, — он не нужен».

Что запомнить

  • __init__ заполняет объект, создаёт его __new__.
  • __repr__ пишут всегда.
  • property вместо геттеров и сеттеров.
  • super() — следующий в MRO, а не родитель.
  • dataclass — для своих структур, Pydantic — для внешних данных.

Проверка урока

Войдите, чтобы проверить себя: сданные проверки всех уроков курса отмечают его темы пройденными на карте и в ИПР.

Вопросы по теме

Читайте также

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования