Что такое наследование python

Наследование в Python 3

Объектно-ориентированное программирование позволяет создавать многоразовые шаблоны кода и таким образом уменьшать количество повторяемых блоков кода в программе. Один из методов, с помощью которого это достигается, называется наследованием; при этом один подкласс может использовать код из другого базового класса.

Данное руководство ознакомит вас с основными аспектами наследования в Python: с работой родительских и дочерних классов, переопределением методов и атрибутов, функцией super() и множественным наследованием.

Что такое наследование?

Наследование подразумевает, что дочерний класс использует код, созданный в родительском классе.

Дочерний класс, или подкласс – это класс, который наследует код из родительского, или базового класса.

Предположим, что у нас есть класс Parent с переменными last_name, height, и eye_color. Подкласс Child может наследовать эти переменные из класса Parent, то есть повторно использовать этот код. Это позволяет уменьшить объём кода и снизить избыточность.

Родительские классы

Родительский, или базовый класс создаёт шаблон кода, который в дальнейшем может наследоваться дочерними классами. Родительским классом может быть любой класс. Базовые классы – это не просто шаблоны, а полноценные функционирующие классы.

Предположим, у нас есть общий родительский класс Bank_account с дочерними классами Personal_account и Business_account. Многие параметры классов Personal_account и Business_account будут совпадать. Такие параметры можно наследовать из родительского класса Bank_account. В подклассе Business_account будут индивидуальные параметры (например, методы сбора деловых документов и форм и переменная employee_identification_number).

Аналогичным образом, класс Animal может содержать методы eating() и sleeping(), а подкласс Snake помимо вышеперечисленных наследуемых методов может также содержать методы hissing() и slithering().

Для примера попробуйте создать родительский класс Fish (в дальнейшем мы используем его, чтобы создать различные подклассы с типами рыб).

Создайте файл fish.py и добавьте в него метод конструктора __init__(), который будет содержать переменные first_name и last_name для каждого подкласса (или объекта) Fish.

class Fish:
def __init__(self, first_name, last_name=»Fish»):
self.first_name = first_name
self.last_name = last_name

Переменная last_name содержит строку “Fish”, потому что почти все подклассы будут использовать это значение.

Добавьте в файл другие методы:

class Fish:
def __init__(self, first_name, last_name=»Fish»):
self.first_name = first_name
self.last_name = last_name
def swim(self):
print(«The fish is swimming.»)
def swim_backwards(self):
print(«The fish can swim backwards.»)

Теперь в файле есть методы swim() и swim_backwards(), которые будут наследоваться подклассами.

Добавьте другие атрибуты в метод __init__():

class Fish:
def __init__(self, first_name, last_name=»Fish»,
skeleton=»bone», eyelids=False):
self.first_name = first_name
self.last_name = last_name
self.skeleton = skeleton
self.eyelids = eyelids
def swim(self):
print(«The fish is swimming.»)
def swim_backwards(self):
print(«The fish can swim backwards.»)

Создание родительского класса ничем не отличается от создания обычного класса. Единственный нюанс: нужно заранее продумывать, какие параметры смогут наследовать дочерние классы.

Дочерние классы

Дочерние классы, или подклассы – это классы, которые наследуют параметры родительских классов. Каждый дочерний класс сможет использовать методы и переменные родительского класса.

К примеру, дочерний класс Goldfish может наследовать из класса Fish функцию swim().

Дочерние классы начинаются немного иначе. В первой строке нужно передать родительский класс:

Класс Trout является дочерним по отношению к классу Fish (родительский класс нужно указать в круглых скобках).

В дочернем классе можно добавить больше методов, переопределить методы родительского класса или просто принять его методы с помощью ключевого слова pass, например:

.
class Trout(Fish):
pass

Теперь создайте объект Trout и наследуйте методы родительского класса, не добавляя новых:

.
class Trout(Fish):
pass
terry = Trout(«Terry»)
print(terry.first_name + » » + terry.last_name)
print(terry.skeleton)
print(terry.eyelids)
terry.swim()
terry.swim_backwards()

Теперь в файле есть объект Trout, который использует все методы класса Fish несмотря на то, что они не объявлены в самом объекте. Нужно только передать значение “Terry” переменной first_name; все остальные переменные уже инициализированы.

Запустите программу. Вы получите:

Terry Fish
bone
False
The fish is swimming.
The fish can swim backwards.

Создайте другой дочерний класс, теперь уже добавив новые методы. Класс будет называться Clownfish, его индивидуальный метод – live_with_anemone.

.
class Clownfish(Fish):
def live_with_anemone(self):
print(«The clownfish is coexisting with sea anemone.»)

Создайте объект Clownfish:

.
casey = Clownfish(«Casey»)
print(casey.first_name + » » + casey.last_name)
casey.swim()
casey.live_with_anemone()

Запустив программу, вы получите такой вывод:

Casey Fish
The fish is swimming.
The clownfish is coexisting with sea anemone.

Как видите, объект casey использует методы __init__() и swim() родительского класса Fish и индивидуальный метод live_with_anemone().

Если попробовать использовать метод live_with_anemone() в объекте Trout, получится ошибка:

terry.live_with_anemone()
AttributeError: ‘Trout’ object has no attribute ‘live_with_anemone’

Это потому, что метод live_with_anemone() принадлежит исключительно дочернему классу Clownfish.

Переопределение методов родительского класса

Только что вы создали дочерний класс Trout, который с помощью ключевого слова pass полностью наследует методы родительского класса Fish, и дочерний класс Clownfish, который не только наследует методы родительского класса, но и использует свой собственный метод.

Однако в некоторых случаях нужно использовать не все, а только отдельные методы родительского класса. Для этого методы родительского класса можно переопределять.

Создавая родительский и дочерний класс, важно учитывать проектирование программы, чтобы переопределение не создало ненужного или избыточного кода.

Для примера создайте дочерний класс Shark. При создании класса Fish использовался параметр skeleton=”bone”, но в случае с классом Sharkэто неверно. Переопределите этот параметр.

Примечание: Что касается проектирования программы, если бы переопределяемый параметр использовался несколькими классами, а не одним, лучше было бы создать для них отдельный родительский класс.

Переопределите метод конструктора __init__() и метод swim_backwards(). Метод swim() изменять не нужно. Дочерний класс будет выглядеть так:

.
class Shark(Fish):
def __init__(self, first_name, last_name=»Shark»,
skeleton=»cartilage», eyelids=True):
self.first_name = first_name
self.last_name = last_name
self.skeleton = skeleton
self.eyelids = eyelids
def swim_backwards(self):
print(«The shark cannot swim backwards, but can sink backwards.»)

Параметры метода конструктора __init__() были переопределены; теперь переменная last_name имеет значение “Shark”, переменная skeleton имеет значение “cartilage”, а eyelids – значение True.

Метод swim_backwards() теперь выводит другое значение, а не то, которое определено в родительском классе Fish.

Теперь создайте экземпляр класса Shark, который будет использовать метод swim() родительского класса Fish.

.
wally = Shark(«Wally»)
print(wally.first_name + » » + wally.last_name)
wally.swim()
wally.swim_backwards()
print(wally.eyelids)
print(wally.skeleton)

Запустите этот код, и вы получите:

Wally Shark
The fish is swimming.
The shark cannot swim backwards, but can sink backwards.
True
cartilage

В дочернем классе Shark методы __init__() и swim_backwards() успешно переопределены.

Функция super()

С помощью функции super() вы можете получить доступ к унаследованным методам, которые были перезаписаны в объекте класса.

Функция super() вызывает родительский метод в дочерний и использует его. Например, это позволяет переопределить один из аспектов родительского метода, а затем вызвать остальную часть исходного родительского метода.

К примеру, в программе, которая выставляет оценки студентам, внутри родительского класса Grade может быть дочерний класс Weighted_grade. В классе Weighted_grade можно переопределить метод родительского класса calculate_grade() и унаследовать остальные методы без изменений. Для этого и нужна функция super().

Обычно функция super() используется в методе конструктора __init__(), потому что именно там, скорее всего, появятся уникальные методы дочернего класса.

Попробуйте изменить дочерний класс Trout. Добавьте переменную water в метод __init__() и присвойте ей значение “freshwater”. Остальные методы родительского класса можно наследовать без изменений.

.
class Trout(Fish):
def __init__(self, water = «freshwater»):
self.water = water
super().__init__(self)
.

Метод __init__() класса Trout был переопределён. Он иначе реализует методы __init__() родительского класса Fish. В методе __init__() класса Trout был явно инициализирован метод __init__() класса Fish.

Поскольку метод переопределён, больше не нужно передавать first_name как параметр Trout. Если бы вы передали параметр, параметр freshwater был бы сброшен. Поэтому переменную first_name нужно инициализировать путём вызова в объекте.

Теперь можно вызвать инициализированные переменные родительского класса, а также использовать уникальную дочернюю переменную.

.
terry = Trout()
# Инициализация first name
terry.first_name = «Terry»
# Использование родительского метода __init__() с помощью функции super()
print(terry.first_name + » » + terry.last_name)
print(terry.eyelids)
# Дочерний метод __init__()
print(terry.water)
# Родительский метод swim()
terry.swim()
Terry Fish
False
freshwater
The fish is swimming.

Как видите, объект terry класса Trout может использовать свой метод __init__() с переменной water и родительский метод __init__() класса Fish с переменными first_name, last_name и eyelids.

Множественное наследование

Множественное наследование подразумевает, что класс может наследовать атрибуты и методы из нескольких родительских классов одновременно. Это позволяет программам сократить избыточность, но также может усложнить код, поэтому множественное наследование нужно использовать только с учетом общей конструкции программы.

Попробуйте создать класс Coral_reef, дочерний по отношению к классам Coral и Sea_anemone. Создайте в каждом классе метод и передайте его с помощью ключевого слова pass в дочерний класс Coral_reef.

class Coral:
def community(self):
print(«Coral lives in a community.»)
class Anemone:
def protect_clownfish(self):
print(«The anemone is protecting the clownfish.»)
class CoralReef(Coral, Anemone):
pass

Класс Coral содержит метод community(), который выводит одну строку текста, а класс Anemone содержит метод protect_clownfish(), который отображает другую строку. После этого оба класса вызываются в кортеж. Таким образом класс Coral может наследовать оба родительских класса.

Читайте также: Кортежи в Python 3

Создайте объект класса Coral:

.
great_barrier = CoralReef()
great_barrier.community()
great_barrier.protect_clownfish()

Объект great_barrier класса CoralReef использует методы обоих родительских классов.

Coral lives in a community.
The anemone is protecting the clownfish.

Как видите, множественное наследование работает правильно.

Множественное наследование позволяет использовать методы нескольких родительских классов внутри одного дочернего класса. Если в родительских классах присутствует один и тот же метод, дочерний класс унаследует его из того родительского класса, который идёт первым в кортеже.

Заключение

Теперь вы знакомы с основами наследования в Python 3 и умеете создавать родительские и дочерние классы, переопределять методы, использовать функцию super() и использовать множественное наследование.

Наследование в объектно-ориентированном программировании позволяет соблюдать принцип разработки DRY («don’t repeat yourself»), благодаря чему программа содержит меньше повторяющихся блоков кода. Наследование также заставляет разработчиков заранее продумывать конструкцию программы.

Источник

Введение в Python

Поиск

Новое на сайте

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

Одним из четырех принципов ООП является наследование (вместе с абстракцией, инкапсуляцией, полиморфизмом).

При создании нового объекта (класса), как в программировании, так и в реальной жизни, мы можем использовать 2 подхода:

Безусловно, второй метод намного эффективнее, проще и требует меньших усилий. Легче вывести новую породу котов скрестив существующие породы, чем пытаться создать животное с нуля.

Возьмем более практический пример. Представим, что перед нами стоит задача запрограммировать класс дерева. Наше дерево имеет следующие атрибуты: вид, возраст и высоту. Так же дерево обладает способностью расти (при этом будет увеличиваться его высота и возраст) и способностью выводить информацию о себе.

Для проверки создадим экземпляр класса дерево и немного поиграем с ним.

Что такое наследование python. Смотреть фото Что такое наследование python. Смотреть картинку Что такое наследование python. Картинка про Что такое наследование python. Фото Что такое наследование python

Теперь представим, что наша задача усложняется: нам необходимо добавить класс фруктового дерева, у которого будут те же атрибуты и методы, но в дополнение появится метод сбора урожая фруктов. Конечно, мы можем создать с нуля класс FruitTree и переписать наново весь код, который будет практически идентичен тому что мы уже написали, но это будет неэффективно, кроме того, нарушается принцип DRY (Don’t Repeat Yourself). Вместо этого мы можем воспользоваться наследованием, то есть создать класс FruitTree и указать ему в качестве родителя класс Tree. Таким образом, FruitTree получит доступ ко всем атрибутам и методам, которыми обладает класс Tree.

Как указать родительский класс в Python.

Родительский класс помещается в скобки после имени класса.

Таким образом, наш код для класса фруктового дерева будет следующим:

Создадим экземпляр класса FruitTree:

Что такое наследование python. Смотреть фото Что такое наследование python. Смотреть картинку Что такое наследование python. Картинка про Что такое наследование python. Фото Что такое наследование python

Зачем использовать наследование.

Концепция наследования в программировании позволяет сократить время разработки, упростить процесс написания программы как сейчас, так и в будущем, когда заказчик захочет внести «небольшие правки» в проект. Правильно спроектированный класс это, кроме прочего, гибкая структура, которую вы свободно сможете изменять, дополнять в будущем. Важно помнить, что иногда проще создать дополнительный базовый класс, наследовать от него и расширять по мере необходимости, чем сразу написать готовый класс.

Источник

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

Наследование – важная составляющая объектно-ориентированного программирования. Так или иначе мы уже сталкивались с ним, ведь объекты наследуют атрибуты своих классов. Однако обычно под наследованием в ООП понимается наличие классов и подклассов. Также их называют супер- или надклассами и классами, а также родительскими и дочерними классами.

Суть наследования здесь схожа с наследованием объектами от классов. Дочерние классы наследуют атрибуты родительских, а также могут переопределять атрибуты и добавлять свои.

Простое наследование методов родительского класса

В качестве примера рассмотрим два класса столов. Класс Table – родительский по отношению к DeskTable (письменные столы). Независимо от своего типа все столы имеют длину, ширину и высоту. Пусть для письменных столов также важна площадь поверхности. Общее вынесем в класс, частное – в подкласс.

Наследственная связь между классами устанавливается через подкласс. При определении дочернего после его имени в скобках указывается родительский.

В данном случае у класса DeskTable нет своего конструктора, поэтому он наследует его от родителя. При создании объектов передавать аргументы необходимо в обоих случаях. Попытка вызова DeskTable с пустыми скобками приведет к ошибке.

С другой стороны, экземпляры надкласса Table, согласно неким родственным связям, не наследуют метод square своего подкласса.

В этом смысле терминология «родительский и дочерний класс» не совсем верна. Наследование в ООП – это скорее аналог систематизации и классификации наподобие той, что есть в живой природе. Все млекопитающие имеют четырехкамерное сердце, но только носороги – рог.

Полное переопределение метода надкласса

Рассмотрим вариант программы с «цепочкой наследования». Пусть дочерний по отношению к Table класс DeskTable в свою очередь выступит родительским по отношению к ComputerTable (компьютерные столы):

Допустим, по задумке разработчиков рабочая поверхность компьютерного стола может вычисляться за вычетом площади, которую занимает монитор. В результате метод square в ComputerTable имеет отличия.

Определив в дочернем классе метод, одноименный методу родительского, мы тем самым переопределяем метод родительского класса. При вызове square на экземпляры ComputerTable будет вызываться метод из этого класса, а не из родительского класса DeskTable.

В то же время ComputerTable наследует конструктор класса от своей «бабушки» – класса Table.

Дополнение, оно же расширение, метода

Часто требуется не столько заменить, то есть полностью переопределить, метод родительского класса в дочернем, сколько дополнить, то есть расширить, код метода родительского класса в дочернем. В таких случаях решением является вызов метода надкласса в теле соответствующего метода подкласса. Обычно после этого в теле метода подкласса пишется дополнительный код.

Пусть имеется подкласс кухонных столов, для которых необходимо еще одно поле – количество посадочных мест. Из-за этой детали мы вынуждены в дочернем классе переопределить конструктор родительского.

Поскольку существенная часть кода конструктора подкласса является такой же как в надклассе, правильнее будет вызвать метод другого класса, а не дублировать код:

Здесь в теле конструктора KitchenTable мы вызываем метод __init__ через объект-класс Table, а не через объект-экземпляр. Вспомним, что в таких случаях метод вызывается как обычная функция (объект, к которому применяется метод, не передается в качестве первого аргумента). Поэтому в конструктор надкласса мы «вручную» передаем текущий экземпляр (self), записывая его перед остальными аргументами.

У кода выше есть небольшой недостаток. Нам ничего не мешает (при условии совпадения количества параметров) вызвать конструктор другого класса, а не только родительского, указав его имя вместо Table. Кроме того, имя надкласса может измениться, и тогда есть риск неправильных обращений к нему из дочерних классов.

В Python c целью улучшения так называемой обслуживаемости кода можно использовать встроенную в язык функцию super. Наиболее распространенным вариантом ее применения является вызов метода родительского класса из метода подкласса:

В данном случае аргумент self в скобках вызываемого родительского метода указывать явно не требуется.

Параметры со значениями по умолчанию у родительского класса

Рассмотрим случай, когда родительский класс имеет параметры со значениями по умолчанию, а дочерний – нет:

При таком определении классов можно создать экземпляр от Table без передачи аргументов для конструктора:

Когда создается объект от дочернего класса, сначала вызывается его конструктор, если он есть. Интерпретатор еще не знает, что в теле этого конструктора будет вызван конструктор родительского класса. Ведь это не обязательно. Значит, если все параметры дочернего конструктора не имеют значений по умолчанию, при построении объекта все значения должны передаваться.

Поэтому, если требуется допустить создание объектов от дочернего класса без передачи аргументов, придется назначить значения по умолчанию также в конструкторе дочернего класса.

Поэтому лучше, когда методы родственных классов принимают одинаковое число параметров. А если разное, то у «лишних» должны быть значения по-умолчанию, чтобы при вызове конструктора их можно было бы не передавать. Если такие параметры находятся еще и в конце, передачу аргументов для предстоящих параметров можно выполнять без ключей.

Другой вариант – отказаться от конструктора в дочернем классе, а значение для поля places устанавливать отдельным вызовом метода:

Здесь у всех кухонных столов по-умолчанию будет 4 места. Если мы хотим изменить значение поля places, можем вызвать метод set_places(). Хотя в случае Python можем сделать это напрямую, присвоив полю. При этом у экземпляра появится собственное поле places.

Поэтому метод set_places() в общем-то не нужен.

В любом случае произвольное количество мест будет устанавливаться не в конструкторе, а отдельно. Если все же требуется указывать места при создании объекта, это можно сделать и в конструкторе родителя:

С помощью функции isinstance() проверяется, что создаваемый объект имеет тип KitchenTable. Если это так, то у него появляется поле places.

Мы не используем параметр p со значением по умолчанию в заголовке конструктора потому, что, если объектам других родственных классов он не нужен, не происходило путаницы и сложностей с документированием кода.

Практическая работа

Разработайте программу по следующему описанию.

В некой игре-стратегии есть солдаты и герои. У всех есть свойство, содержащее уникальный номер объекта, и свойство, в котором хранится принадлежность команде. У солдат есть метод «иду за героем», который в качестве аргумента принимает объект типа «герой». У героев есть метод увеличения собственного уровня.

В основной ветке программы создается по одному герою для каждой команды. В цикле генерируются объекты-солдаты. Их принадлежность команде определяется случайно. Солдаты разных команд добавляются в разные списки.

Измеряется длина списков солдат противоборствующих команд и выводится на экран. У героя, принадлежащего команде с более длинным списком, увеличивается уровень.

Отправьте одного из солдат первого героя следовать за ним. Выведите на экран идентификационные номера этих двух юнитов.

Курс с примерами решений практических работ:
android-приложение, pdf-версия

С. Шапошникова © 2021

Объектно-ориентированное программирование на Python

Источник

Основы наследования в Python

Наследование в Python – важный аспект объектно-ориентированной парадигмы. Наследование обеспечивает возможность повторного использования кода в программе, потому что мы можем использовать существующий класс для создания нового класса вместо того, чтобы создавать его с нуля.

При наследовании дочерний класс получает свойства и может получить доступ ко всем элементам данных и функциям, определенным в родительском классе. Дочерний класс также может предоставлять свою конкретную реализацию функциям родительского класса. В этом разделе руководства мы подробно обсудим основы наследования в Python.

В python производный класс может наследовать базовый класс, просто указав базу в скобках после имени производного класса. Рассмотрим следующий синтаксис, чтобы наследовать базовый класс в производный класс.

Что такое наследование python. Смотреть фото Что такое наследование python. Смотреть картинку Что такое наследование python. Картинка про Что такое наследование python. Фото Что такое наследование python

Класс может наследовать несколько классов, указав их все внутри скобок. Рассмотрим следующий синтаксис.

Многоуровневое наследование Python

Многоуровневое наследование возможно в Python, как и в других объектно-ориентированных языках. Архивируется, когда производный класс наследует другой производный класс. Нет ограничений на количество уровней, до которых многоуровневое наследование архивируется в python.

Что такое наследование python. Смотреть фото Что такое наследование python. Смотреть картинку Что такое наследование python. Картинка про Что такое наследование python. Фото Что такое наследование python

Синтаксис многоуровневого наследования приведен ниже.

Множественное наследование в Python

Python предоставляет нам маневренность для наследования нескольких базовых классов в дочернем классе.

Что такое наследование python. Смотреть фото Что такое наследование python. Смотреть картинку Что такое наследование python. Картинка про Что такое наследование python. Фото Что такое наследование python

Синтаксис для выполнения множественного наследования приведен ниже.

Метод issubclass(sub, sup)

Метод issubclass(sub, sup) используется для проверки отношений между указанными классами. Он возвращает true, если первый класс является подклассом второго класса, и false в противном случае.

Рассмотрим следующий пример:

Метод isinstance(obj, class)

Метод isinstance() используется для проверки взаимосвязи между объектами и классами. Он возвращает true, если это первый параметр, а Obj является экземпляром второго параметра, т. е. классом.

Рассмотрим следующий пример.

Переопределение метода

Мы можем предоставить некоторую конкретную реализацию метода родительского класса в нашем дочернем классе. Когда метод родительского класса определен в дочернем классе с некоторой конкретной реализацией, эта концепция называется переопределением метода. Нам может потребоваться выполнить переопределение метода в сценарии, когда в дочернем классе требуется другое определение метода родительского класса.

Рассмотрим следующий пример, чтобы выполнить переопределение метода в Python.

Реальный пример переопределения метода –

Абстракция данных в Python

Абстракция – важный аспект объектно-ориентированного программирования. В python мы также можем выполнять скрытие данных, добавляя двойное подчеркивание (___) в качестве префикса к атрибуту, который необходимо скрыть. После этого атрибут не будет виден за пределами класса через объект.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *