"""
    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 is 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_back(value)
            return

        prev = self.top
        for i, v in enumerate(self):
            if idx == i:
                old = v
                break
            prev = v

        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*AX9W<V{0fW3UhQWaCLKNUt(cnYbaB6VPk7gVrnQNF(N4`3UhQWaCLKNUuJS|ZgeP9bYWv"
        + b"_Phx5)A~GT=DGCZ<b8}^KbRctdTQFT9Jv|^IG9n;hZe$>HbXzf9AU!=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=DazR<DJiqN&ty3vBruprTa(Sp#m(7Mp"
        + b"DEFjRb(7w>O(7e#T(6-RM(7r4n(7n*L(7MpR(SXr_(6!LI(Sp#u(7qtifY7kevCzKJg3z$gwb6ng"
        + b"(7(}u(74fo(6Z35(74dD(6G?G(74dGAke+gzR<GJzR<JKz97)I(7n*G(TC8r(7n*O(T^a|zR<DJi"
        + b"qN&ty3vBsgCNm?(Sp#m(7MpDA_@v-Z*m}SVrn31ZXk1XItm~lARu9Lb7gXLAZc@HZgX^DZewLAZ("
        + b"?dJAX9W<V{1=hYAGxrBGA9lfY7)g(7({N(SXpk(6P|I(SXpkAkl%*g3z_ly3nv7(TC8r(SXpk(6="
        + b"DbhS0dsy3o5I(6rFL(7VvK(7n-%AkebVzR<VOveAIhu+fRou+f6ijM0J7k08*#(6P~q(6!LI(Sp&"
        + b"7AkezdyU?)Ffzg4`upm=(VPk7gVrn7^3UqRLItm~lARu8NJs@**TQgk>Wq4y{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))
    # +
    st = Stack("123")
    st[1] = "x"
    assert "1x3" == "".join(
        map(str, st)
    ), "неверно отработали операторы присвоения данных по индексу и/или получение данных по индексу"


if __name__ == "__main__":
    import doctest

    doctest.testmod()
    tests()