Тест самоперевірки

Наслідування й композиція

Обери відповідь — і одразу побачиш пояснення. Помилитись тут корисніше, ніж на іспиті.

← до лекції
Відповіді0 / 8   правильних: 0
Питання 1 / 8

У ланцюжку Аудіокнига(Книга) → Книга(Видання) метод «опис» визначено у Видання і в Книга, але не в Аудіокнига. Що поверне аудіокнига.опис()?

Чому так. Пошук атрибута йде кортежем __mro__ зліва направо: Аудіокнига → Книга → Видання → object, і перший знайдений виграє. Аудіокнига нічого не робить — вона просто не заважає пошуку йти далі. AttributeError буває лише тоді, коли методу немає ніде, включно з object.
Питання 2 / 8

Похідний клас має власний __init__, у якому забули викликати super().__init__(...). Коли програма впаде?

Чому так. Створення обʼєкта проходить успішно — обʼєкт просто виходить неповним, без частини атрибутів, і жодного попередження немає. Падіння станеться потім, з AttributeError, і traceback покаже рядок усередині базового методу, а не місце справжньої помилки. Атрибути не «успадковуються»: вони зʼявляються тоді, коли якийсь __init__ їх запише.
Питання 3 / 8

Ромб: class БФП(Сканер, Принтер), Сканер(Пристрій), Принтер(Пристрій), і кожен метод «запустити» друкує своє імʼя й кличе super().запустити(). Скільки рядків надрукується?

Чому так. MRO дорівнює (БФП, Сканер, Принтер, Пристрій, object) — плаский список без повторів, і super() проходить його рівно один раз. Варіант із двома «Пристроями» — це те, що виходить при прямих викликах Сканер.запустити(self) і Принтер.запустити(self): обидва доходять до спільного предка окремо. Порядок цілком передбачуваний і задається порядком класів у дужках.
Питання 4 / 8

У тілі Сканер.запустити написано super().запустити(). Метод викликали на обʼєкті класу БФП(Сканер, Принтер). Куди потрапить цей super()?

Чому так. super() означає «наступний у MRO класу обʼєкта», а не «мій батько», — і Принтер не є базовим для Сканера взагалі. Саме завдяки цьому спільний предок у ромбі виконується один раз. Відповідь «у Пристрій» правильна лише для обʼєкта самого класу Сканер, де MRO інший.
Питання 5 / 8

Каталог має три незалежні виміри: носій (3 варіанти), мова (2) і оправа (2). У скільки нових класів обійдеться додати четвертий носій?

Чому так. При наслідуванні підклас покриває цілу комбінацію, тому новий носій вимагає 2 × 2 = 4 класи — по одному на кожну пару «мова + оправа». При композиції носій — це один маленький клас, який просто кладуть у поле. Важливо: якщо вимір лише один, різниці немає взагалі (1 проти 1), і саме тому наслідування спершу здається доречним.
Питання 6 / 8

Функція друкує каталог, викликаючи x.опис(). У каталозі є НастільнаГра — вона не походить від Видання, але метод «опис» у неї є. Що зміниться, якщо додати перевірку if isinstance(x, Видання)?

Чому так. isinstance питає «якого ти роду», а функції потрібне вміння — і гра вміє рівно те, що треба. Надійності перевірка не додає: успадкувати Видання й не написати опис ніхто не заважає. Якщо тиха перевірка справді потрібна, питай про вміння прямо — hasattr(x, "опис").
Питання 7 / 8

Похідний клас перевизначив метод «опис» і склав рядок сам, без super(). Що станеться з ним, коли формат опису зміниться в базовому класі?

Чому так. Без super() метод похідного класу не звертається до базового ніяк, тож базовий код просто перестає виконуватись — і будь-яка зміна в ньому проходить повз. Це і є різниця між заміною й розширенням: варіант із super() отримує зміну задарма. Жодних попереджень Python тут не дає — перевизначення для нього цілком законне.
Питання 8 / 8

Базовий клас успадковує ABC і має метод, позначений @abstractmethod. Нащадок цей метод не реалізував. Коли Python поскаржиться?

Чому так. Клас із нереалізованим абстрактним методом вважається незавершеним, і Python забороняє створювати його обʼєкти — помилка виникає на Афіша(...), а не десь потім. Варіант із AttributeError на виклику — це поведінка без abc, і вся цінність abc саме в тому, що помилка переїжджає на два кроки раніше, ближче до причини.