Модуль 10
Классы и ООП: модель дрона в коде
4 блок(ов) теории · 10 заданий · 155 баллов
Класс — это чертёж, который собирает данные и поведение в одну сущность; так рождается объектно-ориентированное программирование (ООП). Описание начинается со слова class: class Drone: объявляет класс-чертёж дрона, а создание объекта — вызов класса со скобками: drone = Drone("Модуль", 1150). В момент вызова Python находит в классе метод __init__ (по два подчёркивания с каждой стороны) и выполняет его: def __init__(self, name, dry_mass_g): получает те же аргументы, что переданы в скобках, и заполняет свежесозданный объект. Первый параметр self — сам объект: Python подставляет его автоматически, руками его не передают. Данные объекта называются атрибутами и создаются присваиванием self.имя = ...: self.name = name сохранит имя внутри объекта, чтение — через точку: drone.name — это "Модуль". Атрибута, который __init__ не создавал, у объекта нет: чтение drone.speed упадёт с ошибкой AttributeError — «такого имени нет» (имена ошибок уже встречались: KeyError в модуле 5, TypeError в модуле 6; систематически их читают в модуле 8).
Метод — функция, объявленная внутри класса; он вызывается через точку у объекта: drone.add_payload(500). От функций модуля 6 метод отличается тем, что видит объект через self и может менять его атрибуты. Изменение атрибутов — это состояние: __init__ начинает накопление с нуля (self.payload_g = 0), метод add_payload прибавляет груз (self.payload_g = self.payload_g + g), и значение переживает вызов — следующий add_payload прибавит уже к накопленному. Состояние живёт в объекте, а не в локальных переменных вызова, которые исчезали в конце функции. Бывают и атрибуты класса — записанные прямо в теле класса, без self: motors = 4. Такой атрибут один на все объекты класса, его переопределяют в подклассах; атрибут объекта (self.payload_g) у каждого свой: два дрона не делят груз. Числа модуля — с настоящей платформы: квадро «Модуль» — 1150 г без АКБ, АКБ LiPo 6S 5000 mAh с банками по 3.7 В, полезная нагрузка до 1200 г; окто-апгрейд — 1680 г и до 2800 г; whoop «Мини» — 32 г с АКБ 1S 450 mAh.
Печать объекта — отдельная тема. print(drone) для класса без подготовки напечатает служебную строку вида <__main__.Drone object at 0x7f…>: имя класса и адрес в памяти, свой у каждого запуска. Чтобы печаталось по-человечески, в классе определяют метод __str__ — он возвращает (именно return, без print внутри) готовую строку, и print печатает её: def __str__(self): return f"{self.name}: {self.dry_mass_g} г" — и print(drone) покажет Модуль: 1150 г; f-строки из модуля 1 работают как обычно.
Наследование — способ получить существующий класс, ничего не копируя: class OctoDrone(QuadDrone): объявляет подкласс. Окто-апгрейд получает все атрибуты и методы базового квадро и добавляет своё. Переопределение — повторное объявление: если в подклассе записать motors = 8 и свой motor_failure_safe, эти имена работают по-новому у октокоптера, а у квадро остаются прежними. Живой кейс платформы: квадро «Модуль» за полчаса дополняется вторым этажом из четырёх соосных моторов и превращается в окто — класс тот же, поведение другое: квадро при отказе мотора садится (метод отвечает False), окто на соосной схеме X8 держит горизонт (True). Родство проверяет функция isinstance(объект, класс): объект подкласса проходит проверку на базовый класс, но не наоборот — квадро не является октокоптером.
Задания
0/10 заданий · 0/155 баллов
1. Класс и объект: self, метод, AttributeError
10 балл(ов)Класс Battery: __init__(self, cells) сохраняет cells как атрибут; метод volts() возвращает self.cells * 3.7. Программа: batt = Battery(1), затем print(batt.volts()), затем print(batt.power). Выберите вариант, где верно назван вывод, объяснено, что произойдёт со второй строкой, и правильно сказано, чем метод отличается от функции.