Учебники

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

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

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

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

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

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

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

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

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

Теперь посмотрим на приведенный ниже пример —

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

Выход

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

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

Object.Attribute Lookup Hierarchy

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

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

Давайте вкратце рассмотрим пример наследования —

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

Давайте создадим пару классов для участия в примерах —

  • Животное — Класс имитации животного
  • Кошка — подкласс животного
  • Собака — Подкласс Животного

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

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

Python Constructor

Выход

Выходные данные конструктора Python

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

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

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

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

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

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

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

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

Полиморфизм

Выход

Выход полиморфизма

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

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

полиморфный

Переопределение

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

Супер (подкласс, сам) .метод вместо 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__ был расположен в родительском классе в верхнем, потому что у дочернего класса собака или кошка не было метода __init__ в нем. Python использовал поиск атрибутов наследования, чтобы найти __init__ в классе животных. Когда мы создали дочерний класс, сначала он будет искать метод __init__ в классе dog, затем он не найдет его, затем заглянет в родительский класс Animal, найдет там и вызовет его там. Так как дизайн нашего класса стал сложным, мы можем захотеть инициализировать экземпляр, сначала обработав его через конструктор родительского класса, а затем через конструктор дочернего класса.

Конструктор

Выход

Вывод конструктора

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

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

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

Заключение

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

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

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

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

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

__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.

Выход

Выходные данные Python mro

Пример 3

Давайте рассмотрим еще один пример множественного наследования в форме ромба.

Множественное наследование ромбовидной формы

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

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

Порядок разрешения методов

Выход

Метод Разрешение Порядок Вывод

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

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

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

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

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

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

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

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

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

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

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

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

  • Простой метод — определяется вне класса. Эта функция может получить доступ к атрибутам класса путем подачи аргумента экземпляра:

Простой метод — определяется вне класса. Эта функция может получить доступ к атрибутам класса путем подачи аргумента экземпляра:

def outside_func(():
  • Метод экземпляра

Метод экземпляра

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

Метод класса — если нам нужно использовать атрибуты класса

   @classmethod
def cfunc(cls,)
  • Статический метод — не иметь никакой информации о классе

Статический метод — не иметь никакой информации о классе

      @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), но он может принять произвольное количество других параметров.

синтаксис

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

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