from __future__ import annotations from typing import Iterator, Iterable, List, Any class WordCollection(Iterable): """ Concrete Collections provide one or several methods for retrieving fresh iterator instances, compatible with the collection class. """ def __init__(self, collection: List[Any] = []) -> None: self._collection = collection def __iter__(self) -> AlphabeticalOrderIterator: """ The __iter__() method returns the iterator object itself, by default we return the iterator in ascending order. """ return AlphabeticalOrderIterator(self._collection) def get_reverse_iterator(self) -> AlphabeticalOrderIterator: return AlphabeticalOrderIterator(self._collection, reverse=True) def add_item(self, item: Any) -> None: self._collection.append(item) class AlphabeticalOrderIterator(Iterator): """ Concrete Iterators implement various traversal algorithms. These classes store the current traversal position at all times. """ """ `_position` attribute stores the current traversal position. An iterator may have a lot of other fields for storing iteration state, especially when it is supposed to work with a particular kind of collection. """ _position: int = None """ This attribute indicates the traversal direction. """ _reverse: bool = False def __init__(self, collection: WordCollection, reverse: bool = False) -> None: self._collection = collection self._reverse = reverse self._position = -1 if reverse else 0 def __next__(self): """ The __next__() method must return the next item in the sequence. On reaching the end, and in subsequent calls, it must raise StopIteration. """ try: value = self._collection[self._position] self._position += -1 if self._reverse else 1 except IndexError: raise StopIteration() return value