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

Наследование и полиморфизм - это очень важное понятие в Python. Вы должны понять это лучше, если хотите учиться.

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

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

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

В объектно-ориентированной терминологии, когда класс X расширяет класс Y, тогда Y называется супер / родительским / базовым классом, а X называется подклассом / дочерним / производным классом. Здесь следует отметить, что дочерним классам доступны только поля данных и методы, которые не являются частными. Поля и методы частных данных доступны только внутри класса.

синтаксис для создания производного класса -

class BaseClass:
   Body of base class
class DerivedClass(BaseClass):
   Body of derived class

Наследование атрибутов

Теперь посмотрим на пример ниже -

Вывод

Сначала мы создали класс с именем Date и передали объект в качестве аргумента, здесь-объект - это встроенный класс, предоставляемый Python. Позже мы создали еще один класс с именем time и вызвали класс Date в качестве аргумента. Через этот вызов мы получаем доступ ко всем данным и атрибутам класса Date в классе Time. Из-за этого, когда мы пытаемся получить метод get_date из объекта класса Time tm, который мы создали ранее, возможно.

Object.Attribute Lookup Hierarchy

  • Экземпляр
  • Класс
  • Любой класс, от которого наследуется этот класс

Примеры наследования

Давайте в заключение рассмотрим пример наследования -

Давайте создадим пару классов, чтобы участвовать в примерах -

  • Animal - Класс имитирует животное
  • Кошка - подкласс животных
  • Собака - подкласс животных

В Python конструктор класса, используемый для создания объекта (экземпляра) и присвоения значения атрибутам.

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

Вывод

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

Если подкласс пытается унаследовать методы или данные от другого подкласса, он выдает ошибку, как мы видим, когда класс Dog пытается вызвать методы swatstring () из этого класса cat, он выдает ошибку (например, AttributeError в нашем случае).

Полиморфизм («МНОГИЕ ФОРМЫ»)

Полиморфизм - важная особенность определения классов в Python, которая используется, когда вы обычно называете методы в классах или подклассах. Это позволяет функциям использовать сущности разных типов в разное время. Таким образом, он обеспечивает гибкость и слабую связь, так что код можно расширять и легко поддерживать с течением времени.

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

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

Давайте поймем концепцию полиморфизма с нашим предыдущим примером наследования и добавим один общий метод, называемый show_affection, в оба подкласса -

Из примера, который мы видим, он относится к дизайну, в котором объект разного типа может обрабатываться одинаково или, более конкретно, два или более классов с помощью метода с тем же именем или общего интерфейса, потому что один и тот же метод (show_affection в примере ниже) вызывается с любым типом объектов.

Вывод

Итак, все животные проявляют привязанность (show_affection), но по-разному. Таким образом, поведение «show_affection» полиморфно в том смысле, что оно действует по-разному в зависимости от животного. Итак, абстрактная концепция «животных» на самом деле не «show_affection», но у конкретных животных (например, собак и кошек) есть конкретная реализация действия «show_affection».

У самого Python есть классы, которые являются полиморфными. Например, функцию len () можно использовать с несколькими объектами, и все они возвращают правильный вывод на основе входного параметра.

Отмена

В Python, когда подкласс содержит метод, который переопределяет метод суперкласса, вы также можете вызвать метод суперкласса, вызвав

Super (Subclass, self) .method вместо self.method.

пример

class Thought(object):
   def __init__(self):
      pass
   def message(self):
      print("Thought, always come and go")

class Advice(Thought):
   def __init__(self):
      super(Advice, self).__init__()
   def message(self):
      print('Warning: Risk is always involved when you are dealing with market!')

Наследование конструктора

Если мы видим из нашего предыдущего примера наследования, __init__ был расположен в родительском классе вверху, потому что в дочернем классе dog или cat не было метода __init__. Python использовал поиск атрибутов наследования, чтобы найти __init__ в классе животных. Когда мы создали дочерний класс, сначала он будет искать метод __init__ в классе dog, затем он не нашел его, затем заглянул в родительский класс Animal, нашел там и вызвал его там. Так как дизайн нашего класса стал сложным, мы можем захотеть инициализировать экземпляр, сначала обрабатывая его через конструктор родительского класса, а затем через конструктор дочернего класса.

Вывод

В приведенном выше примере у всех животных есть имя, а у всех собак - особая порода. Мы вызвали конструктор родительского класса с помощью super. Итак, у собаки есть свой __init__, но первое, что происходит, мы называем super. Super - это встроенная функция, которая предназначена для связи класса с его суперклассом или его родительским классом.

В этом случае мы говорим, что получаем суперкласс dog и передаем экземпляр dog любому методу, который мы здесь называем конструктором __init__. Другими словами, мы вызываем родительский класс Animal __init__ с объектом dog. Вы можете спросить, почему мы просто не скажем Animal __init__ с экземпляром dog, мы могли бы сделать это, но если бы имя класса животных изменилось, когда-нибудь в будущем. Что, если мы хотим изменить иерархию классов, чтобы собака унаследовала от другого класса. Использование super в этом случае позволяет нам сохранять модульность и простоту изменения и обслуживания.

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

Заключение

  • __init__ похож на любой другой метод; это может быть унаследовано

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

  • Как только он его находит, Python вызывает его и перестает искать

  • Мы можем использовать функцию super () для вызова методов в родительском классе.

  • Мы можем захотеть инициализировать как родительский, так и наш собственный класс.

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

Как видно из названия, множественное наследование в Python - это когда класс наследуется от нескольких классов.

Например, ребенок наследует черты личности от обоих родителей (матери и отца).

Синтаксис множественного наследования Python

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

Ниже приведен пример этого -

>>> class Mother:
   pass

>>> class Father:
   pass

>>> class Child(Mother, Father):
   pass

>>> issubclass(Child, Mother) and issubclass(Child, Father)
True

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

Вот почему на диаграмме ниже Python сначала выполняет поиск метода dothis () в классе A. Таким образом, порядок разрешения метода в приведенном ниже примере будет

Mro- D→B→A→C

Посмотрите на приведенную ниже диаграмму множественного наследования -

Давайте рассмотрим пример, чтобы понять функцию «mro» в Python.

Вывод

Пример 3

Возьмем еще один пример множественного наследования «ромбовидной формы».

Приведенная выше диаграмма будет считаться неоднозначной. Из нашего предыдущего примера, понимающего «порядок разрешения методов» .ie mro будет D → B → A → C → A, но это не так. При получении второго A от C Python проигнорирует предыдущий A., поэтому mro в этом случае будет D → B → C → A.

Давайте создадим пример на основе приведенной выше диаграммы -

Вывод

Простое правило для понимания вышеприведенного вывода: если тот же класс появляется в порядке разрешения метода, более ранние появления этого класса будут удалены из порядка разрешения метода.

В заключение -

  • Любой класс может наследовать от нескольких классов

  • Python обычно использует порядок «сначала глубина» при поиске наследующих классов.

  • Но когда два класса наследуются от одного и того же класса, Python удаляет первые появления этого класса из mro.

Декораторы, статические методы и методы классов

Функции (или методы) создаются с помощью оператора def.

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

Мы можем классифицировать методы в зависимости от их поведения, например

  • Simple method- определены вне класса. Эта функция может получить доступ к атрибутам класса, передав аргумент экземпляра:

def outside_func(():
  • Instance method -

def func(self,)
  • Class method - если нам нужно использовать атрибуты класса

@classmethod
def cfunc(cls,)
  • Static method - нет информации о классе

@staticmethod
def sfoo()

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

Метод класса

Декоратор @classmethod - это встроенный декоратор функции, которому передается класс, для которого он был вызван, или класс экземпляра, для которого он был вызван, в качестве первого аргумента. Результат этой оценки затеняет определение вашей функции.

синтаксис

class C(object):
   @classmethod
   def fun(cls, arg1, arg2, ...):
      ....
fun: function that needs to be converted into a class method
returns: a class method for function

У них есть доступ к этому аргументу cls, он не может изменять состояние экземпляра объекта. Для этого потребуется доступ к себе.

  • Он привязан к классу, а не к объекту класса.

  • Методы класса по-прежнему могут изменять состояние класса, которое применяется ко всем экземплярам класса.

Статический метод

Статический метод не принимает ни параметров self, ни cls (class), но может принимать произвольное количество других параметров.

syntax

class C(object):
   @staticmethod
   def fun(arg1, arg2, ...):
   ...
returns: a static method for function funself.
  • Статический метод не может изменять ни состояние объекта, ни состояние класса.
  • Они ограничены в том, какие данные они могут получить.

Когда использовать что

  • Обычно мы используем метод класса для создания фабричных методов. Фабричные методы возвращают объект класса (аналогичный конструктору) для разных вариантов использования.

  • Обычно мы используем статические методы для создания служебных функций.