Класс Stack Python

klass stack python Структуры данных

Наибольшим, пожалуй, недостатком стека, основанного на модуле, является поддержка только одного объекта стека. Все клиенты модуля stack фактически пользуются одним и тем же стеком. Иногда такая особенность нужна: стек может служить объектом памяти, совместно используемой несколькими модулями. Но для реализации стека как настоящего типа данных необходимо использовать классы.

Для иллюстрации определим полнофункциональный класс стека. Класс Stack, представленный в примере 18.2, определяет новый тип данных с разнообразным поведением. Как и модуль, для хранения помещаемых на стек объектов класс использует список Python. Но на этот раз каждый экземпляр имеет собственный список. В классе определены как «обычные» методы, так и специальные методы с особыми именами, реализующие стандартные операции над типом данных. Комментарии в программном коде описывают специальные методы.

Пример 18.2. PP4E\Dstruct\Basic\stack2.py

"класс стека, позволяющий создавать множество экземпляров"

class error(Exception): pass # при импортировании: локальное исключение

class Stack:

def __init__(self, start=[]): # self — объект экземпляра self.stack = [] # start — любая последовательность: stack

for x in start: self.push(x) self.reverse() # переупорядочивает операции push

# в обратном порядке

def push(self, obj): # методы: подобно модулю + self

self.stack = [obj] + self.stack # вершина в начале списка

def pop(self):

if not self.stack: raise error(‘underflow’) top, *self.stack = self.stack return top

def top(self):

if not self.stack: raise error(‘underflow’) return self.stack[0]

def empty(self): return not self.stack # instance.empty()

# методы перегрузки операторов def __repr__(self):

return ‘[Stack:%s]’ % self.stack # print, repr(),..

def __eq__(self, other):

return self.stack == other.stack # ‘==’, ‘!=’?

def __len__(self):

return len(self.stack) # len(instance), not instance

def __add__(self, other):

return Stack(self.stack + other.stack) # instance1 + instance2

def __mul__(self, reps):

return Stack(self.stack * reps) # instance * reps

def __getitem__(self, offset): # смотрите также __iter__

return self.stack[offset] # instance[i], [i:j], in, for

def __getattr__(self, name):

return getattr(self.stack, name) # instance.sort()/reverse()/..

Теперь можно создавать отдельные экземпляры обращением к имени класса Stack как к функции. Во многих отношениях операции в классе Stack реализованы точно так же, как в модуле stack из примера 18.1. Но здесь доступ к стеку выполняется через аргумент self, объект экземпляра. Каждый экземпляр имеет свой атрибут stack, который ссылается на собственный список экземпляра. Кроме того, экземпляры стеков создаются и инициализируются в методе конструктора __init__, а не при импортировании модуля. Создадим несколько стеков и посмотрим, как все это действует на практике:

>>> from stack2 import Stack

>>> x = Stack() # создать объект стека, поместить

# в него данные

>>> x.push(‘spam’)

>>> x.push(123)

>>> x # __repr__ выведет содержимое стека

[Stack:[123, ‘spam‘]]

>>> y = Stack() # два независимых объекта стека

>>> y.push(3.1415) # они не используют совместно данные

>>> y.push(x.pop())

>>> x, y

([Stack:[‘spam‘]], [Stack:[123, 3.1415]])

>>> z = Stack() # третий независимый объект стека

>>> for c in ‘spam’: z.push(c)

>   >> while z: # __len__ проверит истинность стека

print(z.pop(), end=’ ‘)

m a p s

>>> 

>  >> z = x + y # __add__ реализует операцию + над стеком

>  >> z # хранит три объекта разных типов

[Stack:[‘spam’, 123, 3.1415]]

>  >> for item in z: # __getitem__ используется в итерациях

print(item, end=’ ‘)

spam 123 3.1415

>>> 

>  >> z.reverse() # вызов __getattr__ передается списку

>  >> z

[Stack:[3.1415, 123, ‘spam’]]

Подобно спискам и словарям класс Stack определяет методы и операторы для обработки операций выражений и обращения к атрибутам. Кроме того, он определяет специальный метод __getattr__ для перехвата обращений к атрибутам, не определенным в классе, и передачи их обернутому объекту списка (для поддержки методов списка: sort, append, reverse и так далее). Многие операции модуля превратились в операции в классе. В табл. 18.3 показаны эквивалентные операции модуля и класса (колонки 1 и 2) и приводится метод класса, который выполняет каждую из них (колонка 3).

Табли ца 18.3. Срав не ние опера ций мо дуля/клас са

Операции в модуле

Операции в классе

Метод класса

module.empty()

not instance

_ len

module.member(x)

x in instance

_ getitem

module.item(i)

instance[i]

_ getitem

module.length()

len(instance)

_ len

module.dump()

print(instance)

_ repr

range() счет чик циклов

for x in instance

_ getitem

вып ол не ние ите ра ций вруч ную

instance + instance

_ add

module.stack.reverse()

instance.reverse()

_ getattr

module.push/pop/top

instance.push/pop/top

push/pop/top

 

В сущности, классы позволяют расширять набор встроенных типов Python с помощью многократно используемых типов, реализуемых в модулях Python. Основанные на классах типы могут использоваться так же, как встроенные типы: в зависимости от того, какие методы операций в них определены, классы могут реализовывать числа, отображения и последовательности и быть изменяемыми или нет. Основанные на классах типы могут также занимать положение, промежуточное между этими категориями.

Использованная литература:

Марк Лутц — Программирование на Python, 4-е издание, II том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий