Как мы видели, классы поддерживают возможность создания нескольких экземпляров и лучше интегрируются с объектной моделью Python благодаря определению методов операторов. Одной из других важных причин использования классов является возможность дальнейшего расширения и настройки. Реализуя стеки с помощью класса, можно в дальнейшем добавлять подклассы, точнее определяющие реализацию в соответствии с возникшими требованиями. В действительности, эта причина часто является основной, из-за которой предпочтение отдается собственным классам, а не встроенным альтернативам.
Допустим, например, что мы стали использовать класс Stack из примера 18.2, но столкнулись с проблемами производительности. Один из способов выявить узкие места состоит в том, чтобы оснастить структуры данных логикой, ведущей статистику использования, которую можно проанализировать после выполнения клиентских приложений. Так как Stack является классом, такую новую логику можно добавить в подклассе, не трогая исходный модуль стека (или его клиентов). Подкласс в примере 18.3 расширяет класс Stack, вводя слежение за суммарной частотой операций push/pop и регистрируя максимальный размер каждого экземпляра.
Пример 18.3. PP4E\Dstruct\Basic\stacklog.py
"расширяет стек возможностью сбора статистики об использовании данных"
from stack2 import Stack # расширяет импортируемый класс Stack
class StackLog(Stack): # подсчитывает операции push/pop, макс. размер
pushes = pops = 0 # разделяемые/статические члены класса
def __init__(self, start=[]): # могут быть переменными модуля self.maxlen = 0
Stack.__init__(self, start)
def push(self, object):
Stack.push(self, object) # выполнить операцию push
StackLog.pushes += 1 # общая статистика
self.maxlen = max(self.maxlen, len(self)) # статистика экземпляра
def pop(self):
StackLog.pops += 1 # общий счетчик
return Stack.pop(self) # не ‘self.pops’: экземпляр
def stats(self) return self.maxlen, self.pushes, self.pops # вернуть счетчики # экземляра
Этот подкласс действует так же, как и оригинальный класс Stack: в него просто добавлена логика мониторинга. Новый метод stats возвращает кортеж со статистикой экземпляра:
> >> from stacklog import StackLog
> >> x = StackLog()
> >> y = StackLog() # создать два объекта стека
> >> for i in range(3): x.push(i) # и поместить в них объекты
…
> >> for c in ‘spam’: y.push(c)
…
> >> x, y # вызов унаследованного метода __repr__
([Stack:[2, 1, 0]], [Stack:[‘m’, ‘a’, ‘p’, ‘s’]])
> >> x.stats(), y.stats()
((3, 7, 0), (4, 7, 0))
>>>
> >> y.pop(), x.pop()
(‘m’, 2)
> >> x.stats(), y.stats() # моя макс. длина, все операции push,
((3, 7, 2), (4, 7, 2)) # все операции pop
Обратите внимание на использование атрибутов клас са для регистрации суммарных количеств операций помещения в стек и выталкивания из стека и атрибутов эк зем п ляра для хранения максимальной длины каждого экземпляра. Добавляя атрибуты к разным объектам, можно расширять или сужать область их действия.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011