Объектный подход: стек с нуля (продолжение)
Теперь давайте пойдем немного дальше. Давайте добавим новый класс для обработки стеков.
Новый класс должен иметь возможность оценивать сумму всех элементов, хранящихся в данный момент в стеке.
Мы не хотим изменять ранее определенный стек. Он уже достаточно хорош в своих приложениях, и мы не хотим, чтобы это каким-либо образом изменилось. Мы хотим новый стек с новыми возможностями. Другими словами, мы хотим создать подкласс уже существующего класса Stack
.
Первый шаг прост: просто определите новый подкласс, указывающий на класс, который будет использоваться в качестве суперкласса.
Вот как это выглядит:
class AddingStack(Stack):
pass
Класс еще не определил новый компонент, но это не значит, что он пуст. Он получает все компоненты, определенные его суперклассом - имя суперкласса записывается после двоеточия непосредственно после имени нового класса.
Это то, что мы хотим от нового стека:
- мы хотим, чтобы метод
push
не только помещал значение в стек, но и добавлял значение в переменнуюsum
; - мы хотим, чтобы функция
pop
не только извлекала значение из стека, но и вычитала значение из переменнойsum
.
Во-первых, давайте добавим новую переменную в класс. Это будет cкрытая переменная, такая как список стеков. Мы не хотим, чтобы кто-либо манипулировал значением sum
.
Как Вы уже знаете, добавление нового свойства в класс выполняется конструктором. Вы уже знаете, как это сделать, но внутри конструктора есть нечто действительно интригующее. Посмотрите:
class AddingStack(Stack):
def __init__(self):
Stack.__init__(self)
self.__sum = 0
Вторая строка тела конструктора создает свойство с именем __sum
- оно будет хранить сумму всех значений стека.
Но строка перед этим выглядит иначе. Что она делает? Это действительно необходимо? Да, это так.
В отличие от многих других языков, Python заставляет Вас явно вызывать конструктор суперкласса. Пропуск этой точки будет иметь пагубные последствия - объект будет лишен списка __stackList
. Такой стек не будет работать должным образом.
Это единственный раз, когда Вы можете явно вызывать любой из доступных конструкторов - это можно сделать внутри конструктора суперкласса.
Обратите внимание на синтаксис:
- Вы указываете имя суперкласса (это класс, конструктор которого Вы хотите запустить);
- Вы ставите точку (
.
) после него; - Вы указываете имя конструктора;
- Вы должны указать на объект (экземпляр класса), который должен быть инициализирован конструктором - вот почему Вы должны указать аргумент и использовать переменную
self
здесь; примечание: вызов любого метода (включая конструкторы) извне класса никогда не требует, чтобы Вы поместили аргументself
в список аргументов - вызов метода изнутри Класс требует явного использования аргументаself
, и он должен быть первым в списке.
Примечание. Обычно рекомендуется вызывать конструктор суперкласса перед любыми другими инициализациями, которые Вы хотите выполнить внутри подкласса. Это правило, которому мы следовали во фрагменте.
Code
class Stack:def __init__(self):
self.__stack_list = []
def push(self, val):
self.__stack_list.append(val)
def pop(self):
val = self.__stack_list[-1]
del self.__stack_list[-1]
return val
class AddingStack(Stack):
def __init__(self):
Stack.__init__(self)
self.__sum = 0