Содержание
Наследование в ООП
Понимание наследования в ООП и классах Python обязательно для понимания.
Рассмотрим простые примеры наследования.
Возьмём код из статьи Python: классы — краткий обзор: аргументы, методы и специальные методы, импорт классов:
class thisIsClass:
'''This is class documentation'''
# зададим два аргумента
arg1 = 'string'
arg2 = 100
# зададим два аргумента - changearg1, changearg2
# и после символа = задаём значения по-умолчанию
def __init__(self, changearg1='Default value 1', changearg2='Default value 2'):
# переопределяем уже созданные аргументы arg1 и arg2
self.arg1 = changearg1
self.arg2 = changearg2
# создадём пустой экземпляр (или "объект") класса
class_instance_def = thisIsClass()
print 'nPrinting default arguments from __init__:'
print (class_instance_def.arg1, class_instance_def.arg2)
# создадём экземпляр (или "объект") класса с аргументами
class_instance_changed = thisIsClass('This is first argument', 'This is second argument')
print 'nPrinting changed arguments from __init__:'
print (class_instance_changed.arg1, class_instance_changed.arg2
В нём мы уже сталкиваемся с понятием «наследование«,так как при создании объекта class_instance_def = thisIsClass() — он наследует все атрибуты класса, к которым мы потом обращаемся:
print (class_instance_def.arg1, class_instance_def.arg2)
Однако, для полноценного понимания и использования наследования в классах — необходимо создать новый класс, который сможет использовать атрибуты своего родительского (или «супер«) класса.
Для этого — создадим новый класс, после имени которого в скобках укажем имя родительского класса:
class thisIsClass:
'''This is class documentation'''
# зададим два аргумента
arg1 = 'string'
arg2 = 100
# зададим два аргумента - changearg1, changearg2
# и после символа = задаём значения по-умолчанию
def __init__(self, changearg1='Default value 1', changearg2='Default value 2'):
# переопределяем уже созданные аргументы arg1 и arg2
self.arg1 = changearg1
self.arg2 = changearg2
# создадём пустой экземпляр (или "объект") класса
class_instance_def = thisIsClass()
print 'nPrinting default arguments from __init__:'
print class_instance_def.arg1
print class_instance_def.arg2
# создадём экземпляр (или "объект") класса с аргументами
class_instance_changed = thisIsClass('This is first argument', 'This is second argument')
print 'nPrinting changed arguments from __init__:'
print class_instance_changed.arg1
print class_instance_changed.arg2
# создаём новый подкласс, который наследует свойства
# класса thisIsClass
class inheritingClass(thisIsClass):
# и имеет собственные аргументы
arg4 = 'value1'
arg5 = 'value2'
# создаём нвоый объект класса
class_inheriting = inheritingClass()
# печатаем собственные аргументы подкласса
print 'nPrinting argument from subclass:'
print class_inheriting.arg4
print class_inheriting.arg5
# и аргументы, унаследованные от родительского класса
print 'nPrinting inherited argument from main class:'
print class_inheriting.arg1
print class_inheriting.arg2
# используем унаследованный метод __init__
# родительского класса, что бы переопределить аргументы
class_inheriting_with_init = inheritingClass('First changed argument from __init__ of main class', 'Second changed argument from __init__ of main class')
print 'nPrinting changed inherited argument from main class:'
print class_inheriting_with_init.arg1
print class_inheriting_with_init.arg2
Результат:
$ ./inherit_class.py Printing default arguments from __init__: Default value 1 Default value 2 Printing changed arguments from __init__: This is first argument This is second argument Printing argument from subclass: value1 value2 Printing inherited argument from main class: Default value 1 Default value 2 Printing changed inherited argument from main class: First changed argument from __init__ of main class Second changed argument from __init__ of main class
Множественное наследование
Подклассу можно указать несколько родительских классов — в таком случае он унаследует все их атрибуты:
Создадим новый код, для удобства чтения:
# создаём первый супер-класс
class mainClass:
arg1 = 'This is argument 1 from class mainClass;'
arg2 = 'This is argument 2 from class mainClass;'
def ext_1(self):
return 'This if method ext_1 from class mainClass.'
# создаём объект суперкласса
main_class = mainClass()
print 'nUsing mainClass:'
print main_class.arg1
print main_class.arg2
print main_class.ext_1()
# создаём сабкласс
# который наследует атрибуты суперкласса mainClass
class firstInherit(mainClass):
arg3 = 'This is argument 3 from class firstInherit;'
arg4 = 'This is argument 4 from class firstInherit;'
def ext_2(self):
return 'This if method ext_2 from class firstInherit.'
first_inherit = firstInherit()
print 'nUsing firstInherit:'
print first_inherit.arg1
print first_inherit.arg2
print first_inherit.arg3
print first_inherit.arg4
print first_inherit.ext_1()
print first_inherit.ext_2()
# создаём второй сабкласс
# который наследует атрибуты классов mainClass и firstInherit
class secondInherit(mainClass, firstInherit):
arg5 = 'This is argument 5 from class firstInherit;'
arg6 = 'This is argument 6 from class firstInherit;'
def ext_3(self):
return 'This if method ext_3 from class secondInherit.'
second_inherit = secondInherit()
print 'nUsing secondInherit:'
print second_inherit.arg1
print second_inherit.arg2
print second_inherit.arg3
print second_inherit.arg4
print second_inherit.arg5
print second_inherit.arg6
print second_inherit.ext_1()
print second_inherit.ext_2()
print second_inherit.ext_3()
Примечание: вместо имён методов ext_N можно было использовать одно и то же имя. Но это уже относится к полиформизму и переопределению методов классов, которые будут рассмотрены позже.
Выполняем скрипт:
$ ./multitype_inheriting.py Using mainClass: This is argument 1 from class mainClass; This is argument 2 from class mainClass; This if method ext_1 from class mainClass. Using firstInherit: This is argument 1 from class mainClass; This is argument 2 from class mainClass; This is argument 3 from class firstInherit; This is argument 4 from class firstInherit; This if method ext_1 from class mainClass. This if method ext_2 from class firstInherit. Using secondInherit: This is argument 1 from class mainClass; This is argument 2 from class mainClass; This is argument 3 from class firstInherit; This is argument 4 from class firstInherit; This is argument 5 from class firstInherit; This is argument 6 from class firstInherit; This if method ext_1 from class mainClass. This if method ext_2 from class firstInherit. This if method ext_3 from class secondInherit.
Поиск атрибутов среди классов
При вызове объекта с атрибутом — интерпретатор бует искать указанный атрибут в описании самого класса, из которого был создан объект; потом — слева направо в указанных ему родительских объектках, потом — в родительских объектах этих родительских объектов (если они есть).
В случае, если аргумент не был найден нигде — будет выдана ошибка:
# создаём первый супер-класс
class mainClass:
arg1 = 'This is argument 1 from class mainClass;'
arg2 = 'This is argument 2 from class mainClass;'
def ext_1(self):
return 'This if method ext_1 from class mainClass.'
# создаём объект суперкласса
main_class = mainClass()
print 'nUsing mainClass:'
print main_class.arg1
# создаём сабкласс
# который наследует атрибуты суперкласса mainClass
class firstInherit(mainClass):
arg3 = 'This is argument 3 from class firstInherit;'
arg4 = 'This is argument 4 from class firstInherit;'
def ext_2(self):
return 'This if method ext_2 from class firstInherit.'
first_inherit = firstInherit()
print 'nUsing firstInherit:'
print first_inherit.arg1
# создаём второй сабкласс
# который наследует атрибуты классов mainClass и firstInherit
class secondInherit(mainClass, firstInherit):
arg5 = 'This is argument 5 from class firstInherit;'
arg6 = 'This is argument 6 from class firstInherit;'
def ext_3(self):
return 'This if method ext_3 from class secondInherit.'
second_inherit = secondInherit()
print 'nUsing secondInherit:'
print second_inherit.arg1
print 'nUsing undefined attribute:'
print second_inherit.arg_undef
Результат:
$ ./multitype_inheriting.py
Using mainClass:
This is argument 1 from class mainClass;
Using firstInherit:
This is argument 1 from class mainClass;
Using secondInherit:
This is argument 1 from class mainClass;
Using undefined attribute:
Traceback (most recent call last):
File "./multitype_inheriting.py", line 44, in <module>
print second_inherit.arg_undef
AttributeError: secondInherit instance has no attribute 'arg_undef'
Как и в других случаях с классами — для сабклассов можно создавать новые атрибуты:
# создаём первый супер-класс
class mainClass:
arg1 = 'This is argument 1 from class mainClass;'
arg2 = 'This is argument 2 from class mainClass;'
def ext_1(self):
return 'This if method ext_1 from class mainClass.'
# создаём объект суперкласса
main_class = mainClass()
print 'nUsing mainClass:'
print main_class.arg1
# создаём сабкласс
# который наследует атрибуты суперкласса mainClass
class firstInherit(mainClass):
arg3 = 'This is argument 3 from class firstInherit;'
arg4 = 'This is argument 4 from class firstInherit;'
def ext_2(self):
return 'This if method ext_2 from class firstInherit.'
first_inherit = firstInherit()
print 'nUsing firstInherit:'
print first_inherit.arg1
# создаём второй сабкласс
# который наследует атрибуты классов mainClass и firstInherit
class secondInherit(mainClass, firstInherit):
arg5 = 'This is argument 5 from class firstInherit;'
arg6 = 'This is argument 6 from class firstInherit;'
def ext_3(self):
return 'This if method ext_3 from class secondInherit.'
second_inherit = secondInherit()
print 'nUsing secondInherit:'
print second_inherit.arg1
print 'nUsing new attribute:'
second_inherit.arg1_new = 'This is new secondInherit class attribute.'
print second_inherit.arg1_new
Результат:
$ ./multitype_inheriting.py Using mainClass: This is argument 1 from class mainClass; Using firstInherit: This is argument 1 from class mainClass; Using secondInherit: This is argument 1 from class mainClass; Using new attribute: This is new secondInherit class attribute.