Python: ООП – наследование классов

Автор: | 21/08/2014
 

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

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