py_stepik/mod_oop/3.8_08_stack.py

184 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
https://stepik.org/lesson/701993/step/8?unit=702094
Ранее вы уже создавали стек-подобную структуру, когда один объект ссылается на следующий и так по цепочке до последнего:
Для этого в программе объявлялись два класса:
StackObj - для описания объектов стека;
Stack - для управления стек-подобной структурой.
И, далее, объекты класса StackObj следовало создавать командой:
obj = StackObj(data)
где data - это строка с некоторым содержимым объекта (данными). При этом каждый объект класса StackObj должен иметь следующие локальные атрибуты:
data - ссылка на строку с данными, указанными при создании объекта;
next - ссылка на следующий объект класса StackObj (при создании объекта принимает значение None).
Класс Stack предполагается использовать следующим образом:
st = Stack() # создание объекта стек-подобной структуры
В каждом объекте класса Stack должен быть локальный публичный атрибут:
top - ссылка на первый объект стека (если стек пуст, то top = None).
А в самом классе Stack следующие методы:
push(self, obj) - добавление объекта класса StackObj в конец стека;
pop(self) - извлечение последнего объекта с его удалением из стека;
Дополнительно в классе Stack нужно объявить магические методы для обращения к объекту стека по его индексу, например:
obj_top = st[0] # получение первого объекта
obj = st[4] # получение 5-го объекта стека
st[2] = StackObj("obj3") # замена прежнего (3-го) объекта стека на новый
Если индекс не целое число или число меньше нуля или больше числа объектов в стеке, то должно генерироваться исключение командой:
raise IndexError('неверный индекс')
Пример использования классов Stack и StackObj (эти строчки в программе не писать):
st = Stack()
st.push(StackObj("obj1"))
st.push(StackObj("obj2"))
st.push(StackObj("obj3"))
st[1] = StackObj("new obj2")
print(st[2].data) # obj3
print(st[1].data) # new obj2
res = st[3] # исключение IndexError
P.S. В программе нужно объявить только классы. Выводить на экран ничего не нужно.
"""
from typing import List
class StackObj:
def __init__(self, data=None):
self.__next = None
self.__data = data
@property
def data(self):
return self.__data
@data.setter
def data(self, value):
self.__data = value
@property
def next(self):
return self.__next
@next.setter
def next(self, value):
if isinstance(value, (self.__class__, None.__class__)):
self.__next = value
def __repr__(self):
return f"{self.__class__.__name__}({self.data!r})"
def __str__(self):
return str(self.data)
class Stack:
def __init__(self, data=None):
self.top = None
if not data:
return
for x in map(lambda x: isinstance(x, StackObj) and x or StackObj(x), data):
self.push(x)
@property
def bottom(self) -> StackObj:
curr, last = self.top, None
while curr:
curr, last = curr.next, curr
return last
def push(self, obj: StackObj):
if not self.top:
self.top = obj
else:
self.bottom.next = obj
def pop(self) -> StackObj:
if not self.top:
return None
a, b, c = [self.top] + [None] * 2
while a:
a, b, c = a.next, a, b
if c:
c.next = None
if self.top in [b, c]:
self.top = None
return b
def __len__(self):
count, obj = 0, self.top
while obj:
obj, count = obj.next, count + 1
return count
def __getitem__(self, idx: int) -> StackObj:
if not isinstance(idx, int) or not 0 <= idx < len(self):
raise IndexError("неверный индекс")
count, obj = 0, self.top
while obj:
if count == idx:
return obj
obj, count = obj.next, count + 1
def __setitem__(self, idx: int, value: StackObj):
if not isinstance(idx, int) or not 0 <= idx <= len(self):
raise IndexError("неверный индекс")
if not isinstance(value, StackObj):
value = StackObj(value)
if idx == len(self):
self.push(value)
return
old = self[idx]
value.next = old.next
if idx > 0:
self[idx - 1].next = value
else:
self.top = value
def get_data(self) -> List[StackObj]:
return [x for x in self]
def __repr__(self):
return f"{self.__class__.__name__}({self.get_data()!r})"
def __str__(self):
return " -> ".join(map(str, self.get_data()))
def tests():
code = (
b"b95j*AX9W<V{0fW3UhQWaCLKNC{uJ{V{1=hYA7OaVrnrlA}J{fb963nb#rJaQ*>ctYfoZoC?ao"
+ b"SYB4e*DJcqbbS`jpb7&}2bYWv_Phx5)B5z`9F*715DGGCRTQOZAJs?wbVPk7gVrnQNZ(?dPEpBCZ"
+ b"A}I=Cb8}^KbRctdTQFTNWMOn+AU!=GB5z`9F)<<_VQyp~b97rVT`pu{bYUPpJs=`)VrnuiZe@2OE"
+ b"FdD#u+f6ifY7+mvC)Ikf*@pJbYURSzR<DJiqN&ty3vBruprR7(7VvE(Sgx{(6As=bYWv_Phx5y(S"
+ b"gvu(6rFC(SXpl(74fpAke+gwa~KAwb6jkz0r%%wII;6(6G?G(7n-%(6u583UqRLItm~lARupIY9K"
+ b"uzb97rXT?%D*V`Xr3AW3dyWq3t$a&K}v3LqdLAYpTJWpZ>NRC0A?3T13_WjYEVARr)Nb8}^KbRb4"
+ b"yY;$ESAR^Gc(6u1ZfzY$iwa~rLwb6jkxY2;nzR<GJu+Y2EzR`ivj3Cgs(Sgvq(7Vx&(TC8r(7n*O"
+ b"(6t~*Ze(S6MRIa)av}-}Z(?d7Js@**E^u#fC@BhIb8}^KbRchHYA$49bYUPpJs=`)VrnrnA}k;x("
+ b"7e#K(Sp#v(6k_MZ*U;cw9vlLyU@1Kwa~pF(Sy*m(6G?E(T~xB(TpI_ztFzXfzZ3qwa~QCz0kPOxg"
+ b"gNK(6P~q(6!LI(Sjh+fzg7{wa~iIuprR5AkebVzR<VOveAIhu+fRou+f6ij3Cgp(6i9KA_@v_AUz"
+ b";33TPlbAaissbZ>A9cW7yBWguue3LqdLAYpTJWpZ>NX>)0Ab97;DV`V64EFe>KVPk7gVrnTYAR^G"
+ b"d(6P~q(6!LI(Sjh+fzg7{wa~iIuprR1(7w>S(6-RE(7hngvC)gsg3*j1(T&i$(6`XF(7e#U(7Vx("
+ b"(SXpt(7Yhfy3o7Ou+f3hfzYrZQ*>ctYfoZoA_^cNARulaD?K1F3LqdLAZQ>xAZRXbWq5Q7ARr(h3"
+ b"So0|WpZ>NZXi89ATlf<BGA3iwa~KAwb6jkz0khUwII=l(74fo(7VvSAke<hvC)dqwa~iJg3!LuvL"
+ b"Mj1Akl%*g3z_ly3n;CDA2OdzR<VOywJYTw$Q!MzAPZnz0k1HfYF1|h|smrz0j~A(6!LB(7qtifzg"
+ b"7|fYF1{y3vBsgVBJ{uqh$"
)
exec(__import__("base64").b85decode(code))
if __name__ == "__main__":
import doctest
doctest.testmod()
tests()