Similar presentations:
Программирование на языке Python Лекция 12. Наследование и полиморфизм
1. Программирование на языке Python
Лекция 12. Наследование иполиморфизм
Заманова С.К.
2.
План лекцииПонятие наследования
Метод super()
Примеры
применения
механизма
наследования в действии
Полиморфизм.
Примеры реализации полиморфизма
3. Объектно-ориентированное программирование
3Объектно-ориентированное программирование
• Объектно-ориентированное программирование
(ООП) — методология программирования, основанная на
представлении программы в виде совокупности объектов,
каждый из которых является экземпляром определённого
класса, а классы образуют иерархию наследования.
• В основе ООП лежит простая и элегантная идея, в
соответствии с которой главное в программе - это данные.
Именно они определяют, какие методы будут
использоваться для их обработки.
• Т. е. данные первичны, код для обработки этих данных вторичен.
4. Свойства объектно-ориентированного программирования
4Свойства объектно-ориентированного программирования
• Наследование (возможность создания новых классов на
базе старых);
• Инкапсуляция (возможность изолирования данных и
методов от остальной части программы);
• Полиморфизм (возможность выполнять одну и ту же
операцию с классами различных типов, если они имеют
общие свойства)..
5. Программирование на языке Python
5Программирование
на языке Python
Наследование в Python
К.Ю. Поляков, Е.А. Ерёмин, 2013
http://kpolyakov.spb.ru
6. Наследование
6Наследование
Механизм наследования позволяет создать новый класс
на основе уже существующего.
При этом новый класс включает в себя как свойства и
методы родительского класса, так и новые (собственные)
атрибуты.
Эти новые атрибуты и отличают свежесозданный класс от
его родителя.
7. Наследование
7Наследование
Для того, чтобы в Python создать новый класс с помощью
механизма наследования, необходимо воспользоваться
следующим синтаксисом:
Синтаксис
class <имя_нового_класса>(<имя_родителя>):
Теперь давайте рассмотрим пример применения
механизма наследования в действии.
Перед нами класс Phone (Телефон), у которого есть одно
свойство is_on и три метода:
Инициализатор: _init_()
Включение: turn_on()
Звонок: call()
8. Наследование
8Наследование
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...')
9. Наследование
9Наследование
В результате объект такого класса получит следующий
набор атрибутов:
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‘.
10. Наследование
10Наследование
А теперь предположим, что мы захотели создать новый
класс - MobilePhone (Мобильный телефон).
Хоть этот класс и новый, но это по-прежнему телефон, а
значит - его все так же можно включить и по нему можно
позвонить.
А раз так, то нам нет смысла реализовывать этот
функционал заново, а можно просто унаследовать его от
класса Phone.
Выглядит это так:
11. Наследование
11Наследование
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...')
12. Наследование
12Наследование
# Унаследованный класс
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}%')
13. Наследование
13Наследование
Как вы видите, в новом классе добавились свойство
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']
14. Наследование
14Наследование
Теперь мы видим, что пользовательские атрибуты состоят
из унаследованных ('is_on', 'call', 'turn_on') и новых ('_init_',
'battery', 'charge').
Все они теперь принадлежат классу MobilePhone.
Пример использования:
Python
# Импортируем оба класса
>>> from phone import Phone, MobilePhone
# Создаем объект класса MobilePhone
>>> my_mobile_phone = MobilePhone()
15. Наследование
15Наследование
# Включаем телефон и делаем звонок
>>> my_mobile_phone.turn_on()
>>> my_mobile_phone.call()
Making call...
# Заряжаем мобильный телефон
>>> my_mobile_phone.charge(76)
Charging battery up to ... 76%
16. Наследование
16Наследование
Что такое super?
Как вы могли заметить, в инициализаторе (метод _init_)
наследуемого класса вызывается метод super(). Что это за
метод и зачем он нужен?
Главная задача этого метода - дать возможность
наследнику обратиться к родительскому классу.
В классе родителе Phone есть свой инициализатор, и
когда в потомке MobilePhone мы так же создаем
инициализатор (а он нам действительно нужен, так как
внутри него мы хотим объявить новое свойство) - мы его
перегружаем.
Иными словами, мы заменяем родительский метод _init_()
собственным одноименным методом.
17. Наследование
17Наследование
Это чревато тем, что родительский метод просто в
принципе не будет вызван, и мы потеряем его функционал
в классе наследнике.
В конкретном случае, потеряем свойство is_on.
Чтобы такой потери не произошло, мы можем:
1. Внутри инициализатора класса-наследника вызвать
инициализатор родителя (для этого вызываем метод
super()._init_())
2. А затем просто добавить новый функционал.
18. Наследование
18Наследование
Давайте еще раз взглянем на метод _init_() класса
MobilePhone:
def __init__(self):
____super().__init__()
____self.battery = 0
Обратите внимание, что вызывать родительский метод
необходимо в первую очередь.
19. Программирование на языке Python
19Программирование
на языке Python
Полиморфизм в Python
К.Ю. Поляков, Е.А. Ерёмин, 2013
http://kpolyakov.spb.ru
20. Полиморфизм
20Полиморфизм
Полиморфизм позволяет перегружать одноименные
методы родительского класса в классах-потомках.
Что дает возможность использовать перегруженный метод
в случаях, когда мы еще не знаем, для какого именно
класса он будет вызван.
Мы просто указываем имя метода, а объект класса, к
которому он будет применен, определится по ходу
выполнения программы.
Базовый класс
Метод Х
Производный класс
Метод Х
21. Полиморфизм
21Полиморфизм
[греч. poly — много и morphe — вид, форма, образ]
Полиморфизм (polymorphism)
имеется несколько реализаций
алгоритма
выбор реализации осуществляется в
зависимости от типа объекта и типа
параметров
Механизмы реализации:
Перегрузка (overload) метода
Переопределение (override) метода
(Химия) В химии свойство тел, одинаковых по химическому составу и построению, принимать различные кристаллические
формы (Графит и Алмаз)
(Биология) Существование особей одного и того же вида с различными по строению формами. Полиморфизм пчел и муравьев.
22. Полиморфизм.
22Полиморфизм.
Пример переопределения методов
Прямоугольник Площадь
Фигура
Площадь
Круг
Площадь
Связывание объекта и метода
Статическое (раннее)
Динамическое (позднее)
23. Полиморфизм
23Полиморфизм
Чтобы стало более понятно, давайте рассмотрим пример:
# Родительский класс
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}')
24. Полиморфизм
24Полиморфизм
# Унаследованный класс
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}')
25. Полиморфизм
25Полиморфизм
# Демонстрационная функция
# Создаем список из классов
# В цикле перебираем список и для каждого элемента
списка (а элемент - это класс)
# создаем объект и вызываем метод info()
# Главная особенность: запись object.info() не дает информацию об объекте, для которого будет вызван метод info()
# Это может быть объект класса Phone, а может - объект
класса MobilePhone
# И только в момент исполнения кода становится ясно,
для какого именно объекта нужно вызывать метод info()
def show_polymorphism():
for item in [Phone, MobilePhone]:
print('-------')
object = item()
object.info()
26. Полиморфизм
26Полиморфизм
Вызываем наш демонстрационный метод:
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
27. Итак:
27Итак:
- Мы с вами узнали, почему при разработке современных
программ использование объектно-ориентированного
подхода является обязательным условием.
- Также разобрались в понятиях Класс, Объект
(Экземпляр), Атрибут, Свойство (Поле), Метод.
- Далее посмотрели, какими эти самые атрибуты, свойства
и методы бывают.
- А еще научились отличать Protected атрибуты от Private и
разобрались, как реализована модель уровней доступа к
атрибутам непосредственно в Python.
- Научились реализовывать наследование и полиморфизм
- Теперь давайте постараемся эти знания применить на
практике.
28. Задача "Покупка дома"
28Задача "Покупка дома"
С помощью подхода ООП и средств Python в рамках данной
задачи необходимо реализовать следующую предметную
структуру:
Классовая структура
• Есть Человек, характеристиками которого являются:
1. Имя
2. Возраст
3. Наличие денег
4. Наличие собственного жилья
• Человек может:
1. Предоставить информацию о себе
2. Заработать деньги
3. Купить дом
29. Задача "Покупка дома"
29Задача "Покупка дома"
• Также же есть Дом, к свойствам которого относятся:
1. Площадь
2. Стоимость
• Для Дома можно:
1. Применить скидку на покупку
• Также есть Небольшой Типовой Дом, обязательной
площадью 40м2.
30. Задание. Часть 1. Класс Human
30Задание. Часть 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.
31. Задание. Часть 1. Класс Human
31Задание. Часть 1. Класс Human
6. Реализуйте приватный метод make_deal(), который будет
отвечать за техническую реализацию покупки дома:
уменьшать количество денег на счету и присваивать ссылку
на только что купленный дом. В качестве аргументов
данный метод принимает объект дома и его цену.
7. Реализуйте метод earn_money(), увеличивающий
значение свойства money.
8. Реализуйте метод buy_house(), который будет проверять,
что у человека достаточно денег для покупки, и совершать
сделку. Если денег слишком мало - нужно вывести
предупреждение в консоль. Параметры метода: ссылка на
дом и размер скидки
32. Задание. Часть 2. Класс House
32Задание. Часть 2. Класс House
1. Создайте класс House
2. Создайте метод __init__() и определите внутри него два
динамических свойства: _area и _price. Свои начальные
значения они получают из параметров метода __init__()
3. Создайте метод final_price(), который принимает в
качестве параметра размер скидки и возвращает цену с
учетом данной скидки.
33. Задание. Часть 3. Класс SmallHouse
33Задание. Часть 3. Класс SmallHouse
1. Создайте класс SmallHouse, унаследовав его
функционал от класса House
2. Внутри класса SmallHouse переопределите метод
__init__() так, чтобы он создавал объект с площадью 40м2
.
34. Задание. Часть 4. Выполнение
34Задание. Часть 4. Выполнение
1. Вызовите справочный метод default_info() для класса
Human
2. Создайте объект класса Human
3. Выведите справочную информацию о созданном объекте
(вызовите метод info()).
4. Создайте объект класса SmallHouse
5. Попробуйте купить созданный дом, убедитесь в
получении предупреждения.
6. Поправьте финансовое положение объекта - вызовите
метод earn_money()
7. Снова попробуйте купить дом
8. Посмотрите, как изменилось состояние объекта
класса Human
programming