- Наследование в Python
- Синтаксис
- Пример использования наследования
- Переопределение методов
- Проверка наследования
- Полиморфизм в Python
- Что такое полиморфизм?
- Пример 1: полиморфизм оператора сложения
- Полиморфизм функций
- Пример 2: полиморфизм на примере функции len()
- Полиморфизм в классах
- Пример 3: полиморфизм в методах класса
- Полиморфизм и наследование
- Пример 4: переопределение метода
Наследование в Python
Наследование — одна из концепций объектно-ориентированного программирования (ООП).
Как было сказано выше, наследование позволяет объявить класс, который либо не отличается от существующего, либо содержит минимальные изменения. Новый класс называется дочерним, а тот, у которого он наследует функционал — родительским.
Синтаксис
class BaseClass:
Тело родительского класса
class DerivedClass(BaseClass):
Тело дочернего класса
Особенность наследования заключается в том, что оно позволяет не просто создать дубликат класса, но и расширить его функционал. Это очень полезно, потому что наследование позволяет повторно использовать уже написанный код.
Пример использования наследования
Полигон — замкнутая геометрическая фигура. У полигона 3 и более сторон.
Давайте объявим класс Polygon :
class Polygon: def __init__(self, no_of_sides): self.n = no_of_sides self.sides = [0 for i in range(no_of_sides)] def inputSides(self): self.sides = [float(input("Введите сторону " + str(i+1)+ " : ")) for i in range(self.n)] def dispSides(self): for i in range(self.n): print("Сторона", i+1, " — ", self.sides[i])
В этом классе объявлено несколько переменных. Одна хранит количество сторон — n . Вторая, sides — это список, в нём находятся размеры сторон.
Метод inputSides() принимает размер каждой стороны, а dispSides() выводит их на экран.
Треугольник — это полигон с 3 сторонами. Теперь мы можем создать класс Triangle , который наследует весь функционал Polygon . Благодаря этому все атрибуты класса Polygon становятся доступны в Triangle .
Так что нам не нужно объявлять все переменные и методы снова. Давайте создадим класс Triangle :
class Triangle(Polygon): def __init__(self): Polygon.__init__(self,3) def findArea(self): a, b, c = self.sides # Вычисляем полупериметр s = (a + b + c) / 2 area = (s*(s-a)*(s-b)*(s-c)) ** 0.5 print('Площадь треугольника равна %0.2f' %area)
В классе есть и собственный метод findArea() . Он вычисляет площадь треугольника и выводит ее на экран. Попробуем запустить нашу программу:
>>> t = Triangle() >>> t.inputSides() Введите сторону 1 : 3 Введите сторону 2 : 5 Введите сторону 3 : 4 >>> t.dispSides() Сторона 1 — 3.0 Сторона 2 — 5.0 Сторона 3 — 4.0 >>> t.findArea() Площадь треугольника равна 6.
Как видите, мы не объявляли методы inputSides() и dispSides() в классе Triangle . Но вот использовать их мы можем!
Если какой-либо атрибут не найдется в дочернем классе, Python пойдет искать в родительской. Этот поиск происходит рекурсивно, если родительский класс одного класса является дочерним для другого.
Переопределение методов
Стоит заметить, что в примере метод __init__() был объявлен в обоих классах — и в Triangle , и в Polygon . Здесь и происходит переопределение классов. То есть, метод в дочернем классе переопределяет тот же самый метод из родительского класса. Это значит, что __init__() в Triangle становится предпочтительнее __init__() в Polygon .
При переопределении метода родительского класса нужно стремиться к его расширению, а не простому копированию. Это, например, происходит при вызове метода в родительском классе из дочернего (вызов P olygon.__init__() из __init__() в Triangle ).
Лучше всего использовать встроенную функцию super() . Например, super().__init__(3) эквивалентно вызову Polygon.__init__(self, 3) . Старайтесь использовать именно этот способ.
Проверка наследования
Для проверки наследования можно использовать две функции: isinstance() и issubclass() .
Функция isinstance() возвращает True , если объект является экземпляром класса или других производных от него классов. Каждый класс в Python является дочерним для какого-либо базового класса.
>>> isinstance(t, Triangle) True >>> isinstance(t, Polygon) True >>> isinstance(t, int) False >>> isinstance(t, object) True
subclass() же используется для проверки, наследуется ли какой-либо класс от другого.
>>> issubclass(Polygon, Triangle) False >>> issubclass(Triangle, Polygon) True >>> issubclass(bool, int) True
СodeСhick.io — простой и эффективный способ изучения программирования.
2023 © ООО «Алгоритмы и практика»
Полиморфизм в Python
В этой статье мы изучим полиморфизм, разные типы полиморфизма и рассмотрим на примерах как мы можем реализовать полиморфизм в Python.
Что такое полиморфизм?
В буквальном значении полиморфизм означает множество форм.
Полиморфизм — очень важная идея в программировании. Она заключается в использовании единственной сущности(метод, оператор или объект) для представления различных типов в различных сценариях использования.
Давайте посмотрим на пример:
Пример 1: полиморфизм оператора сложения
Мы знаем, что оператор + часто используется в программах на Python. Но он не имеет единственного использования.
Для целочисленного типа данных оператор + используется чтобы сложить операнды.
num1 = 1 num2 = 2 print(num1 + num2)
Итак, программа выведет на экран 3 .
Подобным образом оператор + для строк используется для конкатенации.
str1 = "Python" str2 = "Programming" print(str1+" "+str2)
В результате будет выведено Python Programming .
Здесь мы можем увидеть единственный оператор + выполняющий разные операции для различных типов данных. Это один из самых простых примеров полиморфизма в Python.
Полиморфизм функций
В Python есть некоторые функции, которые могут принимать аргументы разных типов.
Одна из таких функций — len() . Она может принимать различные типы данных. Давайте посмотрим на примере, как это работает.
Пример 2: полиморфизм на примере функции len()
print(len("Programiz")) print(len(["Python", "Java", "C"])) print(len())
Здесь мы можем увидеть, что различные типы данных, такие как строка, список, кортеж, множество и словарь могут работать с функцией len() . Однако, мы можем увидеть, что она возвращает специфичную для каждого типа данных информацию.
Полиморфизм в классах
Полиморфизм — очень важная идея в объектно-ориентированном программировании.
Чтобы узнать больше об ООП в Python, посетите эту статью: Python Object-Oriented Programming.
Мы можем использовать идею полиморфизма для методов класса, так как разные классы в Python могут иметь методы с одинаковым именем.
Позже мы сможем обобщить вызов этих методов, игнорируя объект, с которым мы работаем. Давайте взглянем на пример:
Пример 3: полиморфизм в методах класса
class Cat: def __init__(self, name, age): self.name = name self.age = age def info(self): print(f"I am a cat. My name is . I am years old.") def make_sound(self): print("Meow") class Dog: def __init__(self, name, age): self.name = name self.age = age def info(self): print(f"I am a dog. My name is . I am years old.") def make_sound(self): print("Bark") cat1 = Cat("Kitty", 2.5) dog1 = Dog("Fluffy", 4) for animal in (cat1, dog1): animal.make_sound() animal.info() animal.make_sound()
Meow I am a cat. My name is Kitty. I am 2.5 years old. Meow Bark I am a dog. My name is Fluffy. I am 4 years old. Bark
Здесь мы создали два класса Cat и Dog . У них похожая структура и они имеют методы с одними и теми же именами info() и make_sound() .
Однако, заметьте, что мы не создавали общего класса-родителя и не соединяли классы вместе каким-либо другим способом. Даже если мы можем упаковать два разных объекта в кортеж и итерировать по нему, мы будем использовать общую переменную animal . Это возможно благодаря полиморфизму.
Полиморфизм и наследование
Как и в других языках программирования, в Python дочерние классы могут наследовать методы и атрибуты родительского класса. Мы можем переопределить некоторые методы и атрибуты специально для того, чтобы они соответствовали дочернему классу, и это поведение нам известно как переопределение метода(method overriding).
Полиморфизм позволяет нам иметь доступ к этим переопределённым методам и атрибутам, которые имеют то же самое имя, что и в родительском классе.
Давайте рассмотрим пример:
Пример 4: переопределение метода
from math import pi class Shape: def __init__(self, name): self.name = name def area(self): pass def fact(self): return "I am a two-dimensional shape." def __str__(self): return self.name class Square(Shape): def __init__(self, length): super().__init__("Square") self.length = length def area(self): return self.length**2 def fact(self): return "Squares have each angle equal to 90 degrees." class Circle(Shape): def __init__(self, radius): super().__init__("Circle") self.radius = radius def area(self): return pi*self.radius**2 a = Square(4) b = Circle(7) print(b) print(b.fact()) print(a.fact()) print(b.area())
Circle I am a two-dimensional shape. Squares have each angle equal to 90 degrees. 153.93804002589985
Здесь мы можем увидеть, что такие методы как __str__() , которые не были переопределены в дочерних классах, используются из родительского класса.
Благодаря полиморфизму интерпретатор питона автоматически распознаёт, что метод fact() для объекта a (класса Square ) переопределён. И использует тот, который определён в дочернем классе.
С другой стороны, так как метод fact() для объекта b не переопределён, то используется метод с таким именем из родительского класса( Shape ).
Заметьте, что перегрузка методов(method overloading) — создание методов с одним и тем же именем, но с разными типами аргументов не поддерживается в питоне.