JavaRush /Курси /Модуль 1: Python Core /Наслідування

Наслідування

Модуль 1: Python Core
Рівень 9 , Лекція 5
Відкрита

6.1 Наслідування — це просто

Наслідування — це фундаментальна концепція об'єктно-орієнтованого програмування (ООП), яка дозволяє одному класу (званому дочірнім або підкласом) наслідувати поля і методи іншого класу (званого батьківським або суперкласом).

Такий підхід дозволяє створювати більш загальні класи та повторно використовувати код, покращуючи організацію та підтримуваність коду.

Навіщо потрібно наслідування?

Припустимо, тобі потрібно написати якийсь код, і ти вирішив зробити це у вигляді класу. Потім дізнався, що у твоєму проєкті вже існує клас, який робить майже все, що потрібно тобі у твоєму класі. Можеш просто скопіювати код цього класу у свій і користуватися собі на втіху.

А можеш «ніби скопіювати». Можеш оголосити той клас батьком свого класу, і тоді Python додасть твоєму класу поведінку класу батька.

Уяви, що ти природа і хочеш створити Собаку. Що буде швидше — створити собаку з бактерії за мільярд років або одомашнити вовка за 200 тисяч років?

Приклад базового наслідування

Припустимо, у тебе є батьківський клас Animal з полем name:


class Animal:
    def __init__(self, name):
        self.name = name

Хочемо створити 2 класи-нащадки для нього — Dog і Cat, а також додати їм обом метод speak:


class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

У прикладі вище дочірні класи Dog і Cat наслідують від Animal і додають метод speak.

Клас Dog:

  • Наслідує атрибут name з Animal.
  • Додає метод speak, що повертає рядок, специфічний для собак.

Клас Cat:

  • Наслідує атрибут name з Animal.
  • Додає метод speak, що повертає рядок, специфічний для котів.

Фінальний варіант коду виглядає так:


class Animal:
    def __init__(self, name):
        self.name = name
         
class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"
        
class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"
         
dog = Dog("Buddy")
cat = Cat("Whiskers")
        
print(dog.speak())  # Виведе: Buddy says Woof!
print(cat.speak())  # Виведе: Whiskers says Meow!

У цьому прикладі Animal є батьківським класом, а Dog і Cat — дочірніми класами. Дочірні класи наслідують атрибут name і метод __init__ від батьківського класу Animal, але додають методи speak.

6.2 Під капотом у наслідування

Якщо ти додав своєму класу батька, то це дуже схоже на те, наче ти скопіював код класу батька у свій клас.


class Animal:
    def __init__(self, name):
        self.name = name
         

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name)  # Виклик конструктора батьківського класу
        
    def speak(self):
        return f"{self.name} says Woof!"
        
class Cat(Animal):
    def __init__(self, name):
        super().__init__(name)  # Виклик конструктора батьківського класу
        
    def speak(self):
        return f"{self.name} says Meow!"
        

dog = Dog("Buddy")
cat = Cat("Whiskers")
        
print(dog.speak())  # Виведе: Buddy says Woof!
print(cat.speak())  # Виведе: Whiskers says Meow!

Це не зовсім точний опис, але якщо ти ніколи не стикався з концепцією наслідування, то можеш поки думати про неї в такому ключі. Далі ми додамо сюди ще деталей.

6.3 Ієрархія наслідування

Дуже часто, коли проєктується складна модель великої групи класів, ти можеш зіткнутися з цілою ієрархією наслідування.

Наприклад, у тебе є клас Animal — це базовий клас для всіх тварин:


class Animal:
    def __init__(self, name):
        self.name = name
        
    def speak(self):
        raise NotImplementedError("Subclass must implement abstract method")

Ми навіть додали йому метод speak, але так як абстрактна тварина не говорить, цей метод просто кидає виняток NotImplementedError — це стандартна практика.

Потім ми додаємо проміжні класи, які відповідають категоріям тварин: Mammal — це ссавці і Bird для птахів.


class Mammal(Animal):
    def __init__(self, name, fur_color):
        super().__init__(name)  # Виклик конструктора батьківського класу
        self.fur_color = fur_color
         

class Bird(Animal):
    def __init__(self, name, wing_span):
        super().__init__(name)  # Виклик конструктора батьківського класу
        self.wing_span = wing_span
        
    def fly(self):
        return f"{self.name} is flying with a wingspan of {self.wing_span} meters."

І нарешті, тільки на фінальному етапі з'являються класи конкретних видів тварин:


class Dog(Mammal):
    def speak(self):
        return f"{self.name} says Woof!"
         
        
class Cat(Mammal):
    def speak(self):
        return f"{self.name} says Meow!"
        
class Parrot(Bird):
    def speak(self):
        return f"{self.name} says Squawk!"

Ось з ними зазвичай і працює кінцевий код:


animals = [Dog("Buddy", "brown"), Cat("Whiskers", "white"), Parrot("Polly", 0.5)]
            
for animal in animals:
    print(animal.speak())

print(f"{dog.name} has {dog.fur_color} fur.")  # Виведе: Buddy has brown fur.
print(f"{cat.name} has {cat.fur_color} fur.")  # Виведе: Whiskers has white fur.
print(parrot.fly())  # Виведе: Polly is flying with a wingspan of 0.5 meters.

Хоча технічно немає заборон на створення ієрархій з десятками предків, важливо пам'ятати, що без необхідності краще дотримуватися простоти. У простоті сила.

1
Опитування
Класи та ООП, рівень 9, лекція 5
Недоступний
Класи та ООП
Класи та ООП
Коментарі (4)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Andrey Uzhva Рівень 19
26 червня 2025
При використанні моделі виводу return f"{self.brand + " " + self.model} is driving." Жоден з пунктів задачі не пройшов тестування. Чому?
Наталья Крейц Рівень 18
13 липня 2025
Тому що ми вже написали модель взаэмодії f"{......}", ця форма спрощує нам роботу. Все, що буде в кавичках, буде розцінюватись як повноцінний текст. Тобто Ви змішуєте роботу Ф-строчок з контакенацією, що призводить до синтаксичної помилки. Тобто Ви звертаєтесь до програми і кажете: "Виведи мені строку self.brand + " " + self.model", а треба "виведи мені дані {self.brand} {self.model}" Ми пишемо {self.brand}, таким чином явно посилаємось на певний об'єкт даних, з яким взаємодіємо. Тобто це окрема "кімната" для однієї "людини".
Pavlo Kushnir Рівень 26
8 червня 2025
Природа не занимается одомашниванием. Любые домашние животные по уровня развития отстают от диких соплеменников. В первую очередь по интеллекту. Создание домашнего животного - это одбор на ухудшение. В общем, примеры наследования лучше взять другие.
negoda Рівень 31
11 серпня 2025
Никто и не говорит кто отстает а кто превосходит. Конечная цель - создать собаку, и быстрее это сделать одамашнивая волка чем проходить всю цепочку эволюции от бактерии 🤷‍♂️ Нормальный пример.