До этого момента мы писали код в процедурном стиле — функции вызывают другие функции, данные передаются через аргументы. Такой подход работает, но когда программа становится большой, код превращается в спагетти: функции зависят друг от друга, данные размазаны по разным переменным, сложно добавлять новые возможности. Представьте, что вы пишете программу для управления библиотекой. Нужно хранить информацию о книгах, читателях, выдаче книг. В процедурном стиле пришлось бы создавать отдельные списки для названий книг, авторов, годов издания, а затем писать функции, которые работают с этими списками. Это неудобно и чревато ошибками. Именно для решения этих проблем существует объектно-ориентированное программирование (ООП) — парадигма, которая позволяет организовывать код вокруг данных (объектов), а не действий (функций). В ООП мы создаём классы, которые объединяют данные (атрибуты) и поведение (методы) в одной сущности. Например, класс Book может иметь атрибуты title, author, year и метод get_info(), который возвращает информацию о книге. Такой код гораздо легче читать, поддерживать и расширять.
В этом уроке мы начнём изучение ООП — одной из самых важных парадигм в современном программировании. Вы узнаете, что такое классы и объекты. Класс — это «чертёж» или «шаблон», описывающий, какие данные (атрибуты) и какое поведение (методы) будут у объектов. Объект (или экземпляр) — это конкретный представитель класса, имеющий свои собственные значения атрибутов. Например, класс Person описывает, что у человека есть имя и возраст, а объекты этого класса — конкретные люди: person1 = Person("Анна", 25), person2 = Person("Иван", 30).
Мы научимся создавать свои классы с помощью ключевого слова class. Разберём, что такое конструктор __init__ — специальный метод, который вызывается при создании объекта и инициализирует его атрибуты. Конструктор позволяет задать начальные значения атрибутов. Изучим понятие self — ссылки на сам объект, которая передаётся во все методы класса. Благодаря self метод знает, с каким именно объектом он работает. Поймём, почему методы всегда должны принимать self в качестве первого параметра — это особенность Python, которая позволяет методам получать доступ к атрибутам и другим методам текущего объекта.
Особое внимание уделим свойствам — механизму, который позволяет контролировать доступ к атрибутам. В простейшем случае атрибуты доступны напрямую: person.age = -5 — но это небезопасно, потому что возраст не может быть отрицательным. С помощью декоратора @property можно создать метод, который вызывается как обычный атрибут (без скобок), но при этом может выполнять вычисления или проверки. Декораторы @setter и @deleter позволяют контролировать изменение и удаление атрибута. Например, можно создать свойство age, которое при установке проверяет, что возраст положительный.
Также познакомимся со статическими методами (@staticmethod) — методами, которые принадлежат классу в целом, а не конкретному объекту. Они не принимают self или cls и могут использоваться как обычные функции, но логически связаны с классом. Например, статический метод is_valid_age(age) может проверять возраст без создания объекта. Методы класса (@classmethod) получают ссылку на класс в качестве первого аргумента (cls) вместо self. Они часто используются для создания альтернативных конструкторов — например, метода from_string(), который создаёт объект из строки.
Все примеры будут максимально практичными: создадим класс Person для представления человека с атрибутами имени и возраста и методом приветствия; класс BankAccount для банковского счёта с пополнением, снятием и свойством для безопасного доступа к балансу; класс Student для студента с валидацией возраста и оценки через свойства; класс Vector для математического вектора с методами сложения и вычитания. К концу урока вы будете уверенно создавать свои классы и объекты и понимать основные принципы ООП, что станет фундаментом для дальнейшего изучения наследования, полиморфизма и других концепций ООП.