Наследование и полиморфизм

Объектно-ориентированное программирование (ООП) — методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определённого класса, а классы образуют иерархию наследования.

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

Т. е. данные первичны, код для обработки этих данных - вторичен.

Содержимое разработки

Программирование на языке Python Наследование и полиморфизм

Программирование на языке Python

Наследование и полиморфизм

План лекции

План лекции

  • Понятие наследования
  • Метод super()
  • Примеры применения механизма наследования в действии
  • Полиморфизм.
  • Примеры реализации полиморфизма
Объектно-ориентированное программирование

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

  • Объектно-ориентированное программирование (ООП) — методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определённого класса, а классы образуют иерархию наследования.
  • В основе ООП лежит простая и элегантная идея, в соответствии с которой главное в программе - это  данные . Именно они определяют, какие методы будут использоваться для их обработки.
  • Т. е. данные первичны, код для обработки этих данных - вторичен.
Свойства объектно-ориентированного программирования

Свойства объектно-ориентированного программирования

  • Наследование (возможность создания новых классов на базе старых);
  • Инкапсуляция (возможность изолирования данных и методов от остальной части программы);
  • Полиморфизм (возможность выполнять одну и ту же операцию с классами различных типов, если они имеют общие свойства)..
Наследование Механизм наследования позволяет создать новый класс на основе уже существующего. При этом новый класс включает в себя как свойства и методы родительского класса, так и новые (собственные) атрибуты. Эти новые атрибуты и отличают свежесозданный класс от его родителя.

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

Механизм наследования позволяет создать новый класс на основе уже существующего.

При этом новый класс включает в себя как свойства и методы родительского класса, так и новые (собственные) атрибуты.

Эти новые атрибуты и отличают свежесозданный класс от его родителя.

Наследование Для того, чтобы в Python создать новый класс с помощью механизма наследования, необходимо воспользоваться следующим синтаксисом: Синтаксис  class (): Теперь давайте рассмотрим пример применения механизма наследования в действии. Перед нами класс Phone (Телефон), у которого есть одно свойство is_on и три метода:

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

Для того, чтобы в Python создать новый класс с помощью механизма наследования, необходимо воспользоваться следующим синтаксисом:

Синтаксис

class ():

Теперь давайте рассмотрим пример применения механизма наследования в действии.

Перед нами класс Phone (Телефон), у которого есть одно свойство is_on и три метода:

  • Инициализатор: _init_()
  • Включение: turn_on()
  • Звонок: call()
Наследование Python # Родительский класс class Phone :  # Инициализатор  def  __init__( self):  self.is_on = False  # Включаем телефон  def  turn_on (self):  self.is_on = True  # Если телефон включен, делаем звонок  def call (self):  if self.is_on:  print(‘  Making call... ')

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

Python

# Родительский класс

class Phone :

# Инициализатор

def __init__( self):

self.is_on = False

# Включаем телефон

def turn_on (self):

self.is_on = True

# Если телефон включен, делаем звонок

def call (self):

if self.is_on:

print(‘ Making call... ')

my_phone = Phone() dir(my_phone) ['_class_', '_delattr_', '_dict_', '_dir_', '_doc_', '_eq_', '_format_', '_ge_', '_getattribute_', '_gt_', '_hash_', '_init_', '_init_subclass_', '_le_', '_lt_', '_module_', '_ne_', '_new_', '_reduce_', '_reduce_ex_', '_repr_', '_setattr_', '_sizeof_', '_str_', '_subclasshook_', '_weakref_', 'call', 'is_on', 'turn_on'] Среди данной совокупности атрибутов нас больше всего интересуют пользовательские свойства и методы: '_ init_', 'call', 'is_on', 'turn_on‘ ." width="640"

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

В результате объект такого класса получит следующий набор атрибутов:

Python

my_phone = Phone()

dir(my_phone)

['_class_', '_delattr_', '_dict_', '_dir_', '_doc_', '_eq_', '_format_', '_ge_', '_getattribute_', '_gt_', '_hash_', '_init_', '_init_subclass_', '_le_', '_lt_', '_module_', '_ne_', '_new_', '_reduce_', '_reduce_ex_', '_repr_', '_setattr_', '_sizeof_', '_str_', '_subclasshook_', '_weakref_', 'call', 'is_on', 'turn_on']

Среди данной совокупности атрибутов нас больше всего интересуют пользовательские свойства и методы: '_ init_', 'call', 'is_on', 'turn_on‘ .

Наследование А теперь предположим, что мы захотели создать новый класс - MobilePhone (Мобильный телефон). Хоть этот класс и новый, но это по-прежнему телефон, а значит - его все так же можно включить и по нему можно позвонить. А раз так, то нам нет смысла реализовывать этот функционал заново, а можно просто унаследовать его от класса Phone . Выглядит это так:

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

А теперь предположим, что мы захотели создать новый класс - MobilePhone (Мобильный телефон).

Хоть этот класс и новый, но это по-прежнему телефон, а значит - его все так же можно включить и по нему можно позвонить.

А раз так, то нам нет смысла реализовывать этот функционал заново, а можно просто унаследовать его от класса Phone .

Выглядит это так:

Наследование Python class Phone:  def __init__( self):  self.is_on = False  def turn_on (self):  self.is_on = True  def call (self):  if self.is_on:  print(‘ Making call... ')

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

Python

class Phone:

def __init__( self):

self.is_on = False

def turn_on (self):

self.is_on = True

def call (self):

if self.is_on:

print(‘ Making call... ')

Наследование # Унаследованный класс class MobilePhone (Phone):  # Добавляем новое свойство battery  def __init__ (self):  super().__init__()  self.battery = 0 # Заряжаем телефон на величину переданного значения def charge (self, num):  self.battery = num  print(f ' Charging battery up to ... {self.battery}% ')

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

# Унаследованный класс

class MobilePhone (Phone):

# Добавляем новое свойство battery

def __init__ (self):

super().__init__()

self.battery = 0

# Заряжаем телефон на величину переданного значения

def charge (self, num):

self.battery = num

print(f ' Charging battery up to ... {self.battery}% ')

my_mobile_phone = MobilePhone() dir(my_mobile_phone) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'battery', 'call', 'charge', 'is_on', 'turn_on']" width="640"

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

Как вы видите, в новом классе добавились свойство battery и метод charge() . При этом мы помним, что это класс-потомок Phone , а значит от унаследовал и его функционал тоже. Создадим объект нового класса и посмотрим список его атрибутов:

Python

my_mobile_phone = MobilePhone()

dir(my_mobile_phone)

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'battery', 'call', 'charge', 'is_on', 'turn_on']

from phone import Phone, MobilePhone # Создаем объект класса MobilePhone my_mobile_phone = MobilePhone()" width="640"

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

Теперь мы видим, что пользовательские атрибуты состоят из унаследованных ( 'is_on', 'call', 'turn_on ') и новых ('_init_', 'battery', 'charge ').

Все они теперь принадлежат классу MobilePhone .

Пример использования:

Python

# Импортируем оба класса

from phone import Phone, MobilePhone

# Создаем объект класса MobilePhone

my_mobile_phone = MobilePhone()

my_mobile_phone.turn_on() my_mobile_phone.call() Making call... # Заряжаем мобильный телефон my_mobile_phone.charge(76) Charging battery up to ... 76%" width="640"

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

# Включаем телефон и делаем звонок

my_mobile_phone.turn_on()

my_mobile_phone.call()

Making call...

# Заряжаем мобильный телефон

my_mobile_phone.charge(76)

Charging battery up to ... 76%

Наследование Что такое super ? Как вы могли заметить, в инициализаторе (метод _init_ ) наследуемого класса вызывается метод super() . Что это за метод и зачем он нужен? Главная задача этого метода - дать возможность наследнику обратиться к родительскому классу . В классе родителе Phone есть свой инициализатор, и когда в потомке MobilePhone мы так же создаем инициализатор (а он нам действительно нужен, так как внутри него мы хотим объявить новое свойство) - мы его перегружаем . Иными словами, мы заменяем родительский метод _init_() собственным одноименным методом.

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

Что такое super ?

Как вы могли заметить, в инициализаторе (метод _init_ ) наследуемого класса вызывается метод super() . Что это за метод и зачем он нужен?

Главная задача этого метода - дать возможность наследнику обратиться к родительскому классу .

В классе родителе Phone есть свой инициализатор, и когда в потомке MobilePhone мы так же создаем инициализатор (а он нам действительно нужен, так как внутри него мы хотим объявить новое свойство) - мы его перегружаем .

Иными словами, мы заменяем родительский метод _init_() собственным одноименным методом.

Наследование Это чревато тем, что родительский метод просто в принципе не будет вызван, и мы потеряем его функционал в классе наследнике. В конкретном случае, потеряем свойство is_on . Чтобы такой потери не произошло, мы можем: 1. Внутри инициализатора класса-наследника вызвать инициализатор родителя (для этого вызываем метод super()._init_() ) 2. А затем просто добавить новый функционал.

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

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

В конкретном случае, потеряем свойство is_on .

Чтобы такой потери не произошло, мы можем:

1. Внутри инициализатора класса-наследника вызвать инициализатор родителя (для этого вызываем метод super()._init_() )

2. А затем просто добавить новый функционал.

Наследование Давайте еще раз взглянем на метод _init_() класса MobilePhone : def __init__(self): ____super().__init__() ____self.battery = 0 Обратите внимание, что вызывать родительский метод необходимо в первую очередь.

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

Давайте еще раз взглянем на метод _init_() класса MobilePhone :

def __init__(self):

____super().__init__()

____self.battery = 0

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

Полиморфизм Полиморфизм  позволяет перегружать одноименные методы родительского класса в классах-потомках. Что дает возможность использовать перегруженный метод в случаях, когда мы еще не знаем, для какого именно класса он будет вызван. Мы просто указываем имя метода, а объект класса, к которому он будет применен, определится по ходу выполнения программы. Базовый класс Метод Х Производный класс Метод Х

Полиморфизм

  • Полиморфизм позволяет перегружать одноименные методы родительского класса в классах-потомках.
  • Что дает возможность использовать перегруженный метод в случаях, когда мы еще не знаем, для какого именно класса он будет вызван.
  • Мы просто указываем имя метода, а объект класса, к которому он будет применен, определится по ходу выполнения программы.

Базовый класс

Метод Х

Производный класс

Метод Х

Полиморфизм [греч. poly — много и morphe — вид, форма, образ] Полиморфизм  ( polymorphism)  имеется несколько реализаций алгоритма выбор реализации осуществляется в зависимости от типа объекта и типа параметров имеется несколько реализаций алгоритма выбор реализации осуществляется в зависимости от типа объекта и типа параметров Механизмы реализации: Перегрузка ( overload)  метода Переопределение ( override) метода Перегрузка ( overload)  метода Переопределение ( override) метода (Химия) В химии свойство тел, одинаковых по химическому сос-таву и построению, принимать различные кристаллические формы (Графит и Алмаз) (Биология)  Существование особей одного и того же вида с раз-личными по строению формами. Полиморфизм пчел и муравьев. 

Полиморфизм

[греч. poly — много и morphe — вид, форма, образ]

Полиморфизм ( polymorphism)

  • имеется несколько реализаций алгоритма выбор реализации осуществляется в зависимости от типа объекта и типа параметров
  • имеется несколько реализаций алгоритма
  • выбор реализации осуществляется в зависимости от типа объекта и типа параметров

Механизмы реализации:

  • Перегрузка ( overload) метода Переопределение ( override) метода
  • Перегрузка ( overload) метода
  • Переопределение ( override) метода

(Химия) В химии свойство тел, одинаковых по химическому сос-таву и построению, принимать различные кристаллические формы (Графит и Алмаз)

(Биология)  Существование особей одного и того же вида с раз-личными по строению формами. Полиморфизм пчел и муравьев. 

Полиморфизм. Пример переопределения методов Прямоугольник Площадь Фигура Площадь Круг Площадь Связывание объекта и метода Статическое (раннее) Динамическое (позднее)

Полиморфизм.

Пример переопределения методов

Прямоугольник

Площадь

Фигура

Площадь

Круг

Площадь

Связывание объекта и метода

Статическое (раннее)

Динамическое (позднее)

20 Полиморфизм  Чтобы стало более понятно, давайте рассмотрим пример: # Родительский класс class Phone :  def __init__( self):  self.is_on = False   def turn_on (self):  pass  def call (self):  pass # Метод, который выводит короткую сводку по классу Phone  def info (self):  print(f  'Class name: {Phone.__name__}')  print(f  'If phone is ON: {self.is_on}')

20

Полиморфизм

Чтобы стало более понятно, давайте рассмотрим пример:

# Родительский класс

class Phone :

def __init__( self):

self.is_on = False

def turn_on (self):

pass

def call (self):

pass

# Метод, который выводит короткую сводку по классу Phone

def info (self):

print(f 'Class name: {Phone.__name__}')

print(f 'If phone is ON: {self.is_on}')

Полиморфизм # Унаследованный класс class MobilePhone (Phone):  def __init__( self):  super().__init__()  self.battery = 0 # Такой же метод, который выводит короткую сводку по классу MobilePhone # Обратите внимание, что названия у методов совпадают - оба метода называются info() # Однако их содержимое различается  def info (self):  print(f  'Class name: {MobilePhone.__name__}')  print(f  'If mobile phone is ON: {self.is_on}')  print(f  'Battery level: {self.battery}')

Полиморфизм

# Унаследованный класс

class MobilePhone (Phone):

def __init__( self):

super().__init__()

self.battery = 0

# Такой же метод, который выводит короткую сводку по классу MobilePhone

# Обратите внимание, что названия у методов совпадают - оба метода называются info()

# Однако их содержимое различается

def info (self):

print(f 'Class name: {MobilePhone.__name__}')

print(f 'If mobile phone is ON: {self.is_on}')

print(f 'Battery level: {self.battery}')

Полиморфизм # Демонстрационная функция # Создаем список из классов # В цикле перебираем список и для каждого элемента списка  (а элемент - это класс) # создаем объект и вызываем метод info() # Главная особенность: запись object.info() не дает инфор - мацию об объекте, для которого будет вызван метод info() # Это может быть объект класса Phone, а может - объект класса MobilePhone # И только в момент исполнения кода становится ясно, для какого именно объекта нужно вызывать метод info() def show_polymorphism ():  for item in [Phone, MobilePhone]:  print('-------')  object = item()  object.info()

Полиморфизм

# Демонстрационная функция

# Создаем список из классов

# В цикле перебираем список и для каждого элемента списка (а элемент - это класс)

# создаем объект и вызываем метод info()

# Главная особенность: запись object.info() не дает инфор - мацию об объекте, для которого будет вызван метод info()

# Это может быть объект класса Phone, а может - объект класса MobilePhone

# И только в момент исполнения кода становится ясно, для какого именно объекта нужно вызывать метод info()

def show_polymorphism ():

for item in [Phone, MobilePhone]:

print('-------')

object = item()

object.info()

from phone import Phone, MobilePhone from phone import show_polymorphism show_polymorphism() ------- Class name: Phone If phone is ON: False ------- Class name: MobilePhone If mobile phone is ON: False Battery level: 0" width="640"

Полиморфизм

Вызываем наш демонстрационный метод:

Python

from phone import Phone, MobilePhone

from phone import show_polymorphism

show_polymorphism()

-------

Class name: Phone

If phone is ON: False

-------

Class name: MobilePhone

If mobile phone is ON: False

Battery level: 0

Итак: - Мы с вами узнали, почему при разработке современных программ использование объектно-ориентированного подхода является обязательным условием.

Итак:

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

  • Также разобрались в понятиях Класс, Объект (Экземпляр), Атрибут, Свойство (Поле), Метод.
  • Далее посмотрели, какими эти самые атрибуты, свойства и методы бывают.
  • А еще научились отличать Protected атрибуты от Private и разобрались, как реализована модель уровней доступа к атрибутам непосредственно в Python.
  • Научились реализовывать наследование и полиморфизм
  • Теперь давайте постараемся эти знания применить на практике.
Задача

Задача "Покупка дома"

С помощью подхода ООП и средств Python в рамках данной задачи необходимо реализовать следующую предметную структуру:

Классовая структура

  • Есть  Человек , характеристиками которого являются: 1. Имя 2. Возраст 3. Наличие денег 4. Наличие собственного жилья
  • Человек  может: 1. Предоставить информацию о себе 2. Заработать деньги 3. Купить дом
Задача

Задача "Покупка дома"

  • Также же есть  Дом , к свойствам которого относятся: 1. Площадь 2. Стоимость
  • Для  Дома  можно: 1. Применить скидку на покупку
  • Также есть  Небольшой Типовой Дом , обязательной площадью 40м 2 .
Задание. Часть 1. Класс Human 1. Создайте класс  Human .  2. Определите для него два статических поля: default_name и  default_age .  3. Создайте метод  __init__() , который помимо self принимает еще два параметра: name  и  age . Для этих параметров задайте значения по умолчанию, используя свойства  default_name  и  default_age . В методе __init__() определите четыре свойства: Публичные -  name  и  age . Приватные -  money  и  house .  4. Реализуйте справочный метод  info() , который будет выводить поля  name ,  age ,  house  и  money . 5. Реализуйте справочный статический метод  default_info() , который будет выводить статические поля default_name и  default_age .

Задание. Часть 1. Класс Human

1. Создайте класс  Human . 2. Определите для него два статических поля: default_name и  default_age . 3. Создайте метод  __init__() , который помимо self принимает еще два параметра: name  и  age . Для этих параметров задайте значения по умолчанию, используя свойства  default_name  и  default_age . В методе __init__() определите четыре свойства: Публичные -  name  и  age . Приватные -  money  и  house . 4. Реализуйте справочный метод  info() , который будет выводить поля  nameagehouse  и  money .

5. Реализуйте справочный статический метод  default_info() , который будет выводить статические поля default_name и  default_age .

Задание. Часть 1. Класс Human 6. Реализуйте приватный метод  make_deal() , который будет отвечать за техническую реализацию покупки дома: уменьшать количество денег на счету и присваивать ссылку на только что купленный дом. В качестве аргументов данный метод принимает объект дома и его цену.   7. Реализуйте метод  earn_money() , увеличивающий значение свойства money .   8. Реализуйте метод  buy_house() , который будет проверять, что у человека достаточно денег для покупки, и совершать сделку. Если денег слишком мало - нужно вывести предупреждение в консоль. Параметры метода: ссылка на дом и размер скидки

Задание. Часть 1. Класс Human

6. Реализуйте приватный метод  make_deal() , который будет отвечать за техническую реализацию покупки дома: уменьшать количество денег на счету и присваивать ссылку на только что купленный дом. В качестве аргументов данный метод принимает объект дома и его цену. 7. Реализуйте метод  earn_money() , увеличивающий значение свойства money . 8. Реализуйте метод  buy_house() , который будет проверять, что у человека достаточно денег для покупки, и совершать сделку. Если денег слишком мало - нужно вывести предупреждение в консоль. Параметры метода: ссылка на дом и размер скидки

Задание. Часть 2. Класс House 1. Создайте класс  House   2. Создайте метод  __init__()  и определите внутри него два динамических свойства:  _area  и  _price . Свои начальные значения они получают из параметров метода  __init__()   3. Создайте метод  final_price() , который принимает в качестве параметра размер скидки и возвращает цену с учетом данной скидки.

Задание. Часть 2. Класс House

1. Создайте класс  House 2. Создайте метод  __init__()  и определите внутри него два динамических свойства:  _area  и  _price . Свои начальные значения они получают из параметров метода  __init__() 3. Создайте метод  final_price() , который принимает в качестве параметра размер скидки и возвращает цену с учетом данной скидки.

Задание. Часть 3. Класс SmallHouse 1. Создайте класс  SmallHouse , унаследовав его функционал от класса  House   2. Внутри класса  SmallHouse  переопределите метод __init__() так, чтобы он создавал объект с площадью 40м 2 .

Задание. Часть 3. Класс SmallHouse

1. Создайте класс  SmallHouse , унаследовав его функционал от класса  House 2. Внутри класса  SmallHouse  переопределите метод __init__() так, чтобы он создавал объект с площадью 40м 2

.

Задание. Часть 4. Выполнение 1. Вызовите справочный метод  default_info()  для класса Human  2. Создайте объект класса  Human  3. Выведите справочную информацию о созданном объекте (вызовите метод  info() ).  4. Создайте объект класса  SmallHouse  5. Попробуйте купить созданный дом, убедитесь в получении предупреждения.  6. Поправьте финансовое положение объекта - вызовите метод  earn_money()  7. Снова попробуйте купить дом  8. Посмотрите, как изменилось состояние объекта класса  Human

Задание. Часть 4. Выполнение

1. Вызовите справочный метод  default_info()  для класса Human 2. Создайте объект класса  Human 3. Выведите справочную информацию о созданном объекте (вызовите метод  info() ). 4. Создайте объект класса  SmallHouse 5. Попробуйте купить созданный дом, убедитесь в получении предупреждения. 6. Поправьте финансовое положение объекта - вызовите метод  earn_money() 7. Снова попробуйте купить дом 8. Посмотрите, как изменилось состояние объекта класса  Human

Сохранить у себя:
Наследование и полиморфизм

Получите свидетельство о публикации сразу после загрузки работы



Получите бесплатно свидетельство о публикации сразу после добавления разработки