class _ListItem:
def __init__(self, obj, previous, next):
self._obj = obj
self._previous = previous
self._next = next
def get_object(self):
return self._obj
@property
def previous(self):
return self._previous
@property
def next(self):
return self._next
def set_next(self, item):
self._next = item
class LinkedList:
def __init__(self):
self._first = None
self._last = None
self._len = 0
def first(self):
if self._len == 0:
raise IndexError("Empty list")
return self._first.get_object()
def last(self):
if self._len == 0:
raise IndexError("Empty list")
return self._last.get_object()
def _iter(self):
item = self._first
yield item.get_object()
while item.next is not None:
item = item.next
yield item.get_object()
def __iter__(self):
if self._len == 0:
return []
return self._iter()
def add(self, obj):
if self._first is None:
self._first = self._last = _ListItem(obj, None, None)
self._len = 1
else:
item = _ListItem(obj, self._last, None)
self._last.set_next(item)
self._last = item
self._len += 1
def pop(self):
if self._len == 0:
raise IndexError("Empty list")
item = self._last
self._last = item.previous
self._last.set_next(None)
self._len -= 1
if self._len == 0:
self._first = None
return item.get_object()
if __name__ == "__main__":
# test
l = LinkedList()
l.add(1)
l.add("dsfsdfs")
l.add([1, 2, 3])
for x in l:
print(x)
print(l.pop())
print(l.first(), l.last())
Как видите атрибуты _first, _last и _len никак не торчат наружу, поэтому внутри класса вы можете делать с ними что угодно, для юзера все махинации скрыты.