Сколько видов наследования выделяют python
Наследование позволяет создавать новый класс на основе уже существующего класса. Наряду с инкапсуляцией наследование является одним из краеугольных камней объектно-ориентированного программирования.
Ключевыми понятиями наследования являются подкласс и суперкласс . Подкласс наследует от суперкласса все публичные атрибуты и методы. Суперкласс еще называется базовым (base class) или родительским (parent class), а подкласс — производным (derived class) или дочерним (child class).
Синтаксис для наследования классов выглядит следующим образом:
Например, у нас есть класс Person, который представляет человека:
Предположим, нам необходим класс работника, который работает на некотором предприятии. Мы могли бы создать с нуля новый класс, к примеру, класс Employee:
Однако класс Employee может иметь те же атрибуты и методы, что и класс Person, так как работник — это человек. Так, в выше в классе Employee только добавляется метод works , весь остальной код повторяет функционал класса Person. Но чтобы не дублировать функционал одного класса в другом, в данном случае лучше применить наследование.
Итак, унаследуем класс Employee от класса Person:
Класс Employee полностью перенимает функционал класса Person, лишь добавляя метод work() . Соответственно при создании объекта Employee мы можем использовать унаследованный от Person конструктор:
И также можно обращаться к унаследованным атрибутам/свойствам и методам:
Однако, стоит обратить внимание, что для Employee НЕ доступны закрытые атрибуты типа __name. Например, мы НЕ можем в методе work обратиться к приватному атрибуту self.__name :
Множественное наследование
Одной из отличительных особенностей языка Python является поддержка множественного наследования, то есть один класс можно унаследовать от нескольких классов:
Здесь определен класс Employee, который представляет сотрудника фирмы, и класс Student, который представляет учащегося студента. Класс WorkingStudent, который представляет работающего студента, не определяет никакого функционала, поэтому в нем определен оператор pass . Класс WorkingStudent просто наследует функционал от двух классов Employee и Student. Соответственно у объекта этого класса мы можем вызвать методы обоих классов.
При этом наследуемые классы могут более сложными по функциональности, например:
Playing with inheritance in Python
![]()
Inheritance is the capability of one class (child/derived/sub class) to derive or inherit the properties or attributes from some another class (parent/base class) . Inheritance increases reusability of a code. We don’t need to write the same code again and again. Inheritance it allows programmers to add more features to a class or modify the existing behavior.
Simple Inheritance
Have a look at this simple inheritance procedure :
get_name method is defined in Person class not in Employee class. When we inherit from base class (at line 9) we get its properties and attributes to the child class. That’s why we are getting access to get_name method at child class and its objects (at line 18 and 19) .
Attributes, properties or methods of base class will be available to child class but not the vice versa. It we write person.is_employee() then we will face an error like : AttributeError: ‘Person’ object has no attribute ‘employee’ because, is_employee() method defined in child class, not in the parent class.
Multilevel inheritance
Python support multilevel inheritance. When a class is derived from a class which is also derived from another class (a class having more than one parent classes) such inheritance is called Multilevel Inheritance. The level of inheritance can be extended to any number of level depending upon the relation.
Here, class A has only method_from_class_a method, class B has method_from_class_a and method_from_class_b methods (because, class B extends class A) and class C has method_from_class_a , method_from_class_b and method_from_class_c methods (because, class C extends B and class B extends c).
Inheritance is transitive in nature (which means that if class B inherits from another class A, then all the subclasses of B would automatically inherit from class A).
Multiple inheritance
Python supports multiple inheritance, where a class can have multiple parent classes.
Here, class C extends both class A and class B , that’s why methods of class A and class B are available to class C.
Method Resolution Order (MRO)
Let’s start enjoying the game of this article!
Here, we have two speak methods in class A and class B . class C extends both class A and class B . So, class C gets both speak methods. Then what will be output at line 16? Which speak method will be called? Confusing, NO?
For a class hierarchy, Python needs to determine which class to use when attempting to access an attribute by name. To do this, Python considers the ordering of base classes.
For the previous code, speak method of class A will be executed and we will get “class A speaking” output. It we change class C(A, B) (at line, 11) to class (B, A) then speak method of class B will be executed and we will get “class B speaking” output.
Let’s change code of class C like :
Here, speak method of class C will override previous speak method. And c.speak() will print “class C speaking”.
Now, according to our discussion on MRO guess what will be output of this code :
Congratulation! you’re correct! Output will be “A”.
Little philosophy about Inheritance
Consider a relationship scenario like:
Notice that, both Friend and FamilyMember have relationship_details attribute and both of them are identical. If FamilyMember would extend Friend class then we only needed to write family_members attribute in FamilyMember class. But we didn’t do that. Because, it’s not necessarily true that a family member will also be a friend but a family member necessarily will be a person. So, the philosophy is, for inheritance, class structure should reflects the correct relationship among classes.
Some words about `super`
Sometimes we need to call methods of parent class to a overridden method of child class. We can achieve this using super function.We can directly use methods of super class or modify them(this is very common).
We could write class B like:
Look at super(B, self) (here, super takes two arguments: a class and its object). This is another approach of calling super .
Difference between super() and super(className, self):
Python 3 encourages using super() , instead of using super(className,self) , both have the same effect. Python 2, only supports the super(className,self) syntax. Since, Python 2 is widely used so Python 3 also has support for this type of super calling. You more about super here .
Introspection
As python supports different types of inheritance so sometimes it needs to be introspected cleanly.
- isinstance() : isinstance() takes two argument : an object and a class. It returns True if the given class is anywhere in the inheritance chain of the object’s class.
At line 11 we get True because A() is the object of class A .
At line 12 we get True because class A is in the inheritance chain of the class of object B() .
- issubclass() : issubclass() takes two argument (class, class).It returns True if the first class contains the second class anywhere in its inheritance chain.
Output at line 15 seems okay but output at line 16 may look odd. Clearly, Class A is not a subclass of itself ( Class A ), but Python works in this way!
- __bases__() : __bases__() provides a tuple of immediate base classes of a class.
Note : By default, every Python class is the subclass of built-in object class.
- __subclasses__() : __subclasses__() returns a list of all
the subclasses a class. Like __bases__() , __subclasses__ only goes one level deep from the class we’re working on.
- __mro__ : __mro__ is an attributes which contains full MRO (Method Resolution Order) of a class as a tuple.
Another game using __init__ and __new__
Transforming from class to an object is called instantiation. __init__ is used to objects initialization. Inside __init__ function only initialization should be done, nothing more.
This is a sample code using __init__ :
During object creation __init__ method doesn’t get executed first, the method which gets executed first is __new__ . __new__() method gets most of the same arguments at __init__ and it is responsible for actually creating the new object (prior to initializing object) .
We can use __new__ when we need to control the creation of a new instance.
Let we have a 3 classes, File , TextFile(File) and ImageFile(File) . We need instantiate TextFile for Text files, ImageFile for image file, and File for other type of files. We can obtain this by instantiating them directly.
But what if we could instantiate them only using the parent class ( File ) depending the file content? Yes, we want to instantiate child classes using parent class!
Pretty interesting, NO?
Output :
<__main__.TextFile object at 0x7efc02f1d278>
<__main__.ImageFile object at 0x7efc02f1d2b0>
<__main__.File object at 0x7efc02f1d048>
Here, we are instantiating the TextFile , ImageFile and File classes using the File (parent) class depending on content of file ( file_type ). See differences among outputs of line 35, 36 and 37.
That’s all for today’s game!
Happy gaming with Python!
You can also read :
This story is published in Noteworthy, where 10,000+ readers come every day to learn about the people & ideas shaping the products we love.
Follow our publication to see more product & design stories featured by the Journal team.
Наследование#
Наследование является ключевым аспектом ООП и, конечно, доступно в python . Как уже многократно подмечалось ранее, в python всё является объектом. Можно даже сказать больше, любой тип объекта (встроенный или пользовательский) или напрямую или через один из своих базовых классов расширяет тип object .
В частности, следующее объявление класса неявно расширяет object .
Специальный атрибут __bases__ позволяет узнать базовый класс (или классы, python поддерживает множественное наследование). Встроенная функция issubclass возвращает True , отвечает на вопрос, является ли класс указанный в первом аргументе производным от класса указанного во втором аргументе.
Базовый синтаксис#
Допустим, у нас есть базовый класс BaseClass и мы хотим объявить класс DerivedClass , который будет расширять его. Тогда необходимо указать базовый класс в заголовочной строке производного класса в круглых скобках после имени базового класса.
В данном примере заголовок class DerivedClass(BaseClass): сигнализирует, что DerivedClass наследует от BaseClass .
При проверке принадлежности экземпляра производного класса к базовому классу метод isinstance вернет True .
Из-за этой особенности, принято проверять принадлежность к классу именно методом isinstance(obj, cls) , а не выражением вида type(obj) == cls . Это позволяет писать код, который не будет замечать разницы между экземплярами базового и производного классов. В ряде ситуаций область применения такого кода можно будет расширять, не редактируя его.
Наследование атрибутов класса#
Кроме того, производный класс наследует атрибуты и методы базового класса (речь пока идет про атрибуты самого класса, а не экземпляра).
Определим базовый класс с атрибутом attr и со статическим (для удобства вызова) методом method .

Видим, что через объект объявления производного класса DerivedClass удаётся получить доступ к атрибутам и методам базового класса BaseClass .
Механизм наследования атрибутов не совсем очевиден. У объекта объявления производного класса не появляются атрибуты базового класса, но получить доступ к атрибуту базового класса через объект объявления производного класса получается из-за механизма поиска атрибутов класса.
Пусть мы пытаемся выражением C.x получить доступ к атрибуту x класса C , который расширяет класс B . Тогда выполняется следующая процедура.
Атрибут x ищется у класса C . Если он обнаруживается, то он и возвращается;
Если атрибут x у класса C найти не удаётся, то атрибут x ищется у базового класса B .
Второй шаг выполняется рекурсивно, т.е. если B расширяет класс A и в B тоже не удаётся найти атрибут x , то поиск продолжится в классе A (и далее по цепочке наследования).
Доступ к атрибутам базового класса через экземпляр производного класса тоже возможен, т.к. процедура поиска атрибута у экземпляра делегирует этот поиск классу этого экземпляра (см. процедуру выше), если в самом экземпляре нет такого атрибута.
Перекрытие атрибутов#
Если в производном классе есть атрибуты с такими же именами, как и в базовом классе, то они переопределят таковые из базового класса.
Расширим определение производного класса DerivedClass из предыдущего примера его собственными атрибутами attr и method .

Видим, что теперь через объект объявления производного класса вызываются его же методы.
Множественное наследование#
Можно наследовать сразу от нескольких базовых классов. Для этого необходимо указать их через запятую.
В примере DerivedClass наследует сразу от трех классов.
Атрибуты в базовых классах пересекаются: атрибут b есть и у LeftBase и у MiddleBase , атрибут c есть и у MiddleBase и у RightBase . Возникает вопрос, если обратиться от производного класса к этим атрибутам, то значение атрибута какого из базовых классов вернется в качестве результата? Распечатаем атрибуты a , b , c и d класса DerivedClass .
Видим, что возвращается атрибут того базового класса, который указан в списке базовых классов первым (самый левый).
Вызов методов базового класса. Функция super #
Иногда все же возникает необходимость вызвать перекрытый метод базового класса в экземпляре производного класса. Яркий пример — инициализация объекта. При создании объекта необходимо убедиться, что будет вызван и метод __init__ базового класса и метод __init__ производного класса. Обычно этого добиваются вызовом инициализирующего метода базового класса в самом начале инициализирующего метода производного класса.
Неопытному программисту на python может показаться, что этого можно добиться следующим образом:
Но это приведет к рекурсии: метод B.__init__ создаётся на этапе объявления класса, а значит при поиске атрибута self.__init__ найдется именно B.__init__ (у экземпляра self такого атрибута нет, а значит поиск идёт в его классе), а не A.__init__ .
Выход из этой ситуации — вызвать метод A.__init__ явно.
При таком подходе произойдет то, чего мы и добивались. Тем не менее принято делать это иначе, а именно использовать встроенную функцию super. В нашем примере, инструкция
Параметр self при вызове через super передавать не надо!
В таком крошечном примере может показаться, что использование такого подхода с функцией super ни чем не упрощает вызов методов базового класса. Тем не менее принято предпочитать именно его даже в самых простых ситуациях. В более сложных иерархиях классов без функции super сложно обойтись.
Рассмотрим следующую иерархию наследования: South наследует от West и East , каждый из которых в свою очередь расширяют класс North . Хочется, чтобы при инициализации экземпляра класса South вызывались и методы инициализации всех базовых классов. Попробуем реализовать эту схему, указывая все базовые классы явно.
Видим, что метод инициализации класса North вызвался дважды. Первый раз это произошло через класс West , а второй раз через класс East . Теперь заменим все явные упоминания классов через функцию super .
Проблема с тем, что метод инициализации North вызывался дважды, решена! Функция super использует С3-линеаризацию (method resolution order) для определения порядка, в котором вызывать методы классов в иерархии наследования. Но чтобы это работало, необходимо, чтобы везде вызов происходил именно через super .
Абстрактный базовый класс. Абстрактный метод.#
Модуль abc (сокращение от Abstract Base Class ) предоставляет инструменты для реализации абстрактных базовых классов, т.е. классов, которые лишь задают интерфейс и не предназначены для создания экземпляров напрямую. Обычно, абстрактный базовый класс наследует от abc.ABC, а абстрактные методы помечаются декоратором abc.abstractmethod. Производные от такого абстрактного базового класса классы смогут создавать экземпляры, только если они переопределят все абстрактные методы. Если не переопределен хоть один из абстрактных методов, то python возбудит ошибку при попытке создать экземпляр. Так как тело абстрактной функции не играет никакой роли, то в нем часто возбуждают исключение NotImplementedError.
В качестве примера реализуем абстрактный базовый класс Shape для геометрической фигуры. Как и в примере с треугольником, будем считать, что каждая фигура должна уметь считать свой периметр и площадь.
Пять типов наследования в Python
В предыдущей статье мы представили тему ориентированного объектно-ориентированного программирования или OOP для коротких. Затем мы обсудили классы и тему наследования. Эта статья сделает быстрый отвод наследования, то, что оно и почему вы его использовали. Тогда мы представим различные типы наследства, вы можете столкнуться с вашим программированием … Пять типов наследования в Python Подробнее »
- Автор записи
Автор оригинала: David Yeoman.
В оформлении Предыдущая статья Мы представили тему объектно-ориентированного программирования или OOP для коротких. Тогда мы обсуждали классы и тема Наследование Отказ Эта статья сделает Быстрый отвод наследования , что это такое, и почему вы его использовали. Затем мы представим различные типы наследства, вы можете столкнуться с вашим программированием и проиллюстрировать их с примерами кода. Наконец, мы кратко коснусь в вложенном наследстве.
Что означает наследование?
Таким образом, мы знаем, что класс представляет собой план объекта, и он содержит атрибуты и методы. Наследование относится к способности одного класса наследовать атрибуты и методы другого. По сути, он получает использование этих компонентов посредством ссылки на другой класс без необходимости переписать весь необходимый код.
Мы называем эту ассоциацию A Родительские отношения , где ребенок наследует атрибуты родителя. Тем не менее, это наследство может принимать разные формы. В реальном мире мы все знакомы с одним прямым наследством, где ребенок наследует от своего отца, который действительно является одной из форм, используемых в Python. Тем не менее, есть еще более сложные формы, которые мы сейчас обсудим.
Представляем пять видов наследства
Хотя пятый тип наследства по существу является амальгамой предыдущих четырех, есть пять основных форм. Я покажу каждый пример в блочной форме, а затем покажу в коде. Наконец, мы будем использовать пример продуктового магазина, чтобы объяснить типы.
Одиночное наследование
Наиболее основная форма наследования, в этом случае ребенок наследует от одного родителя.
Давайте посмотрим на примере кода, в котором у нас есть класс продуктового магазина, содержащий общедоступные атрибуты продуктов продуктов, который является родительским, и детский класс консервированных элементов, которые имеют атрибуты, специально связанные с банками, такими как объем и производитель.
Вот результат этого фрагмента кода:
В этом примере вы увидели простую связь одного наследования, где атрибуты, такие как фондовый кодекс, описание и т. Д., Принадлежность к родительскому классу под названием Accound, предоставляются для использования ребенка, называемой консервированными. Не только атрибуты доступны, поэтому также являются методами внутри родителя. Например, все дети консервированного класса могут получить доступ и использовать метод Sell_Price для родителя.
Многократное наследование
Несколько наследство возникают, когда есть два или более родительских классов, из которых унаследовать детский класс.
Мы расширим наш пример продуктового магазина, чтобы показать несколько наследний. В следующем коде у нас есть два родительских класса, наш оригинал Сток И другой под названием Склад Отказ Консервированный Класс – это ребенок обоих, наследство Сток Атрибуты и методы и Склад Атрибуты, такие как складское место, упаковка и количество на упаковку.
Давайте посмотрим на результат:
Из кода вы можете увидеть, что когда мы напечатали этикетку на стойке, он содержал атрибуты, нарисованные с обоих родительских классов при использовании метода от детского класса.
Многоуровневое наследство
Мощность наследования – это способность к ребенку класс быть родительским классом другого. Таким образом, чтобы растянуть аналогию, у нас есть дедушка, родитель, дочерние отношения, которые описывают многоуровневое наследство.
В нашем продуктовом магазине я немного отталкиваю границы с примером, но давайте представим, что у нас есть акции в качестве бабушкина, мясной класс как родитель, а также детский класс курицы. Вероятно, не реалистичный пример, но я уверен, что вы получите точку зрения. Вот код.
Результатом этого кода фрагмент выглядит следующим образом:
Курица Детский класс добавил два новых параметра, порцию и состояние. Параметр порции описывает барабанные палатки, бедра, грудь, четверть, половину и целое, в то время как состояние описывает замороженные, свежие или приготовленные. Мы передаем их в атрибуты self.cut и Self.Cond. . Мы получаем доступ к другим атрибутам из родителей, Мясо класс или бабушка, Сток класс. Мы также используем методы со всех трех уровней классов.
Иерархическое наследование
Иерархическое наследство напоминает классическую иерархическую структуру дерева организации. У него есть родитель с несколькими детьми.
При примере продуктового магазина различные категории продуктов – это все дети для родительского класса. Таким образом, у нас есть Консервированный С Мясо и Производить Классы, которые будут получать от родителей Сток Класс для общих атрибутов и методов. Тем не менее, каждый будет добавлять свои атрибуты и методы, специфичные для конкретных потребностей категории.
В этом коде мы назвали конкретные атрибуты и методы каждого класса ребенка, а также успешно вытягивая атрибуты и методы родителя.
Гибридное наследование
Как вы угадаете, гибридный наследство – это просто амальгама других видов наследства.
В нашем продуктовом магазине у нас есть универсальный фондовый класс и класс склада, который оба текут к классу мяса. Под классом мяса у нас есть курица, свинина и говядина. Как видите, тип наследования не имеет очевидного имени, отсюда, отсюда уловки – все гибрид.
Как вы видели, три детских класса, Курица , Свинина и Говядина все удалось получить доступ к Этикетка Метод в родительском классе, который обращался к атрибутам в классах дедушек, чтобы определить расположение места расположения и атрибуты размещения, а затем напрямую доступ к Sell_price Метод в Сток класс.
Резюме
В этой статье мы пополнили наследство в Python, что это такое, и почему вы его использовали. Затем мы представили пять различных типов наследования, которые вы могли бы столкнуться с вашим программированием, прежде чем иллюстрировать их с примерами кода.