Содержание
Наследование в ООП
Понимание наследования в ООП и классах 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.