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

Содержание
Введение
Пример
Пример 2
Пример 3
Порядок атрибутов
*args, **kwargs
Похожие статьи

Введение

Это продолжение статьи «Классы» из раздела «ООП в Python» .

Для лучшего понимания этого материала пригодятся знания из следующих статей: Методы , Класс методы , Статические методы , super() , Декораторы , isinstance()

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

Все классы в Python являются наследниками класса object

Чтобы один класс наследовал от другого нужно при объявлении класса передать родительский класс как аргумент.

class A: pass class B(A): pass

Можно описать отношения между A и B в этом примере большим количеством способов:

Добавим в каждый класс по методу.

class A: def funcA(self): print("A") class B(A): def funcB(self): print("B") b = B() A.funcA = B.funcB b.funcA()

B

Пример

Создадим класс Employee и производный от него класс Developer.

Developer - наследник Employee. Для начала у Developer не будет функционала - просто убедимся, что у объекта производного класса есть те же атрибуты, что и у родитльского. Также проверим что можно применять методы из родительского класса. В конце изучим класс с помощью help.

class Employee: num_of_emps = 0 raise_amt = 1.04 def __init__(self, first, last, pay): self.first = first self.last = last self.pay = pay self.email = first + '.' + last + '@kaspersky.com' Employee.num_of_emps += 1 def fullname(self): return f'{self.first} {self.last}' def apply_raise(self): self.pay = int(self.pay * self.raise_amt) class Developer(Employee): pass dev_1 = Developer('Eugene', 'Kaspersky', 50000) dev_2 = Developer('Test', 'User', 60000) print(dev_1.email) print(dev_2.email) print(dev_1.pay) dev_1.apply_raise() print(dev_1.pay) print(help(Developer))

python inheritance_example.py

Eugene.Kaspersky@kaspersky.com Test.User@kaspersky.com 50000 52000 Help on class Developer in module __main__: class Developer(Employee) | Developer(first, last, pay) | | Method resolution order: | Developer | Employee | builtins.object | | Class methods defined here: | | from_string(emp_str) from builtins.type | | set_raise_amt(amount) from builtins.type | | ---------------------------------------------------------------------- | Static methods defined here: | | is_workday(day) | | ---------------------------------------------------------------------- | Methods inherited from Employee: | | __init__(self, first, last, pay) | Initialize self. See help(type(self)) for accurate signature. | | apply_raise(self) | | fullname(self) | | ---------------------------------------------------------------------- | Data descriptors inherited from Employee: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) | | ---------------------------------------------------------------------- | Data and other attributes inherited from Employee: | | num_of_emps = 2 | | raise_amt = 1.04 (END)

Пример с новыми атрибутами

Добавим классу Developer новый атрибут - язык программирования. Также создадим для этого класса метод __init__()

class Employee: num_of_emps = 0 raise_amt = 1.04 def __init__(self, first, last, pay): self.first = first self.last = last self.pay = pay self.email = first + '.' + last + '@kaspersky.com' Employee.num_of_emps += 1 def fullname(self): return f'{self.first} {self.last}' def apply_raise(self): self.pay = int(self.pay * self.raise_amt) class Developer(Employee): raise_amt = 1.10 def __init__(self, first, last, pay, prog_lang): super().__init__(first, last, pay) # Также можно было написать: # super(Developer, self).__init__(first, last, pay) # или # Employee.__init__(self, first, last, pay) self.prog_lang = prog_lang emp_1 = Employee('Andrei', 'Olegovich', 40000) dev_1 = Developer('Eugene', 'Kaspersky', 50000, 'Python') dev_2 = Developer('Test', 'User', 60000, 'Java') print(f"emp_1 raise_amt: {emp_1.raise_amt}") # 1.04 print(f"dev_1 raise_amt: {dev_1.raise_amt}") # 1.1 print(f"dev_1 Email: {dev_1.email}") print(dev_1.prog_lang) # Python

python inheritance_example.py

emp_1 raise_amt: 1.04 dev_1 raise_amt: 1.1 dev_1 Email: Eugene.Kaspersky@kaspersky.com Python

При созданиее нового девелопера, с помощью super() был переиспользован метод __init__() из класса Employee. Это позволило девелоперу иметь email, хотя в коде объявления про email нет упоминания.

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

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

class Manager(Employee): def __init__(self, first, last, pay, employees=None): super().__init__(first, last, pay) if employees is None: self.employees = [] else: self.employees = employees def add_emp(self, emp): if emp not in self.employees: self.employees.append(emp) def remove_emp(self, emp): if emp in self.employees: self.employees.remove(emp) def print_emps(self): for emp in self.employees: print('-->', emp.fullname()) mgr_1 = Manager('Sue', 'Smith', 90000, [dev_1]) print(mgr_1.fullname()) print(mgr_1.email) mgr_1.print_emps() print("add dev_2") mgr_1.add_emp(dev_2) mgr_1.print_emps() print("remove dev_1") mgr_1.remove_emp(dev_1) mgr_1.print_emps() print(isinstance(mgr_1, Manager)) print(isinstance(mgr_1, Employee)) print(isinstance(mgr_1, Developer)) print(issubclass(Manager, Employee)) print(issubclass(Developer, Employee)) print(issubclass(Manager, Developer))

python inheritance_example.py

Sue Smith Sue.Smith@kaspersky --> Eugene Kaspersky add dev_2 --> Eugene Kaspersky --> Test User remove dev_1 --> Test User True True False True True False

Полный код

class Employee: num_of_emps = 0 raise_amt = 1.04 def __init__(self, first, last, pay): self.first = first self.last = last self.pay = pay self.email = first + '.' + last + '@kaspersky.com' Employee.num_of_emps += 1 def fullname(self): return f'{self.first} {self.last}' def apply_raise(self): self.pay = int(self.pay * self.raise_amt) @classmethod def set_raise_amt(cls, amount): cls.raise_amt = amount @classmethod def from_string(cls, emp_str): first, last, pay = emp_str.split('-') return cls(first, last, pay) @staticmethod def is_workday(day): if day.weekday() == 5 or day.weekday() == 6: return False return True class Developer(Employee): raise_amt = 1.10 def __init__(self, first, last, pay, prog_lang): super().__init__(first, last, pay) # also possible # Employee.__init__(self, first, last, pay) self.prog_lang = prog_lang class Manager(Employee): def __init__(self, first, last, pay, employees=None): super().__init__(first, last, pay) if employees is None: self.employees = [] else: self.employees = employees def add_emp(self, emp): if emp not in self.employees: self.employees.append(emp) def remove_emp(self, emp): if emp in self.employees: self.employees.remove(emp) def print_emps(self): for emp in self.employees: print('-->', emp.fullname()) emp_1 = Employee('Andrei', 'Olegovich', 40000) dev_1 = Developer('Eugene', 'Kaspersky', 50000, 'Python') dev_2 = Developer('Test', 'User', 60000, 'Java') print(f"emp_1 raise_amt: {emp_1.raise_amt}") # 1.04 print(f"dev_1 raise_amt: {dev_1.raise_amt}") # 1.1 print(f"dev_1 Email: {dev_1.email}") print(dev_1.prog_lang) # Python mgr_1 = Manager('Sue', 'Smith', 90000, [dev_1]) print(mgr_1.fullname()) print(mgr_1.email) mgr_1.print_emps() print("add dev_2") mgr_1.add_emp(dev_2) mgr_1.print_emps() print("remove dev_1") mgr_1.remove_emp(dev_1) mgr_1.print_emps() print(isinstance(mgr_1, Manager)) print(isinstance(mgr_1, Employee)) print(isinstance(mgr_1, Developer)) print(issubclass(Manager, Employee)) print(issubclass(Developer, Employee)) print(issubclass(Manager, Developer))

Порядок атрибутов при наследовании

Если у производного класса есть дополнительные атрибуты помимо родительских их можно инициализировать как до так и после взятых у родителя

class Person(object): def __init__(self, name, phone): self.name = name self.phone = phone class Teenager(Person): def __init__(self, name, phone, website): Person.__init__(self, name, phone) self.website=website class Student(Person): def __init__(self, name, phone, website): self.website = website Person.__init__(self, name, phone) t = Teenager("Max", "12345", "http://testsetup.ru") s = Student("Max", "12345", "http://testsetup.ru") print(t.__dict__) print(s.__dict__)

{'name': 'Max', 'phone': '12345', 'website': 'http://testsetup.ru'} {'website': 'http://testsetup.ru', 'name': 'Max', 'phone': '12345'}

Обратите внимание, что у студента сайт идёт первым - до атрибутов имя и телефон, которые взяты у родительского класса персона.

*args, **kwargs

Если у родительского класса очень много атрибутов, иногда чтобы их не писать можно использовать *args, **kwargs

class Person: def __init__(self, name, phone, age, birthday, height, iq): self.name = name self.phone = phone self.age = age self.birthday = birthday self.height = height self.iq = iq class Teenager(Person): def __init__(self, website, *args, **kwargs): self.website = website Person.__init__(self, *args, **kwargs) class Student(Person): def __init__(self, website, *args, **kwargs): self.website = website super().__init__(*args, **kwargs) class Coder(Person): def __init__(self, *args, **kwargs): self.website = args[0] new_args = args[1:] Person.__init__(self, *new_args, **kwargs) class Developer(Person): def __init__(self, *args, **kwargs): self.website = args[0] new_args = args[1:] super().__init__(*new_args, **kwargs) t = Teenager("http://testsetup.ru", "Max", "12345", 15, 20090101, 190, 140) s = Student("http://testsetup.ru", "Max", "12345", 15, 20090101, 190, 140) c = Coder("http://testsetup.ru", "Max", "12345", 15, 20090101, 190, 140) d = Developer("http://testsetup.ru", "Max", "12345", 15, 20090101, 190, 140) print(t.__dict__) print(s.__dict__) print(c.__dict__) print(d.__dict__)

{'website': 'http://testsetup.ru', 'name': 'Max', 'phone': '12345', 'age': 15, 'birthday': 20090101, 'height': 190, 'iq': 140} {'website': 'http://testsetup.ru', 'name': 'Max', 'phone': '12345', 'age': 15, 'birthday': 20090101, 'height': 190, 'iq': 140} {'website': 'http://testsetup.ru', 'name': 'Max', 'phone': '12345', 'age': 15, 'birthday': 20090101, 'height': 190, 'iq': 140} {'website': 'http://testsetup.ru', 'name': 'Max', 'phone': '12345', 'age': 15, 'birthday': 20090101, 'height': 190, 'iq': 140}

Автор статьи: Андрей Олегович

Похожие статьи
ООП в Python
Классы
Методы
class variables
class methods
Статические методы
Наследование
super()
Специальные методы
dataclass
__slots__
Декоратор property
Полиморфизм

РЕКЛАМА хостинга Beget, которым я пользуюсь более десяти лет

Изображение баннера

Конец рекламы хостинга Beget, который я всем рекомендую.

Поиск по сайту

Подпишитесь на Telegram канал @aofeed чтобы следить за выходом новых статей и обновлением старых

Перейти на канал

@aofeed

Задать вопрос в Телеграм-группе

@aofeedchat

Контакты и сотрудничество:
Рекомендую наш хостинг beget.ru
Пишите на info@urn.su если Вы:
1. Хотите написать статью для нашего сайта или перевести статью на свой родной язык.
2. Хотите разместить на сайте рекламу, подходящую по тематике.
3. Реклама на моём сайте имеет максимальный уровень цензуры. Если Вы увидели рекламный блок недопустимый для просмотра детьми школьного возраста, вызывающий шок или вводящий в заблуждение - пожалуйста свяжитесь с нами по электронной почте
4. Нашли на сайте ошибку, неточности, баг и т.д. ... .......
5. Статьи можно расшарить в соцсетях, нажав на иконку сети: