Solution 1

class ListIterable(object):
    def __init__(self, elems):
        self.elems = elems
        self.index = 0

    def __next__(self):
        if self.index >= len(self.elems):
            raise StopIteration()

        elem = self.elems[self.index]
        self.index += 1

        return elem

    next = __next__


class ListIterator(object):
    def __init__(self, elems):
        self.elems = elems

    def __iter__(self):
        return ListIterable(self.elems)

List Iterable

Following our previous assignment, the objetive of this one is to split the iterator from the iterable. You should be able to use your previous implementation for the iterable (you can actually copy and paste the code, removing the __iter__ part). Example:

iterator = ListIterator([3, 2, 1])

for elem in iterator:
    print(elem)
# Prints: 3, 2, 1

print("===============")

for elem in iterator:
    print(elem)
# Prints: 3, 2, 1 AGAIN

Test Cases

test with empty list - Run Test

import pytest

def test_with_empty_list():
    iterator = ListIterator([])
    it = iter(iterator)
    with pytest.raises(StopIteration):
        next(it)

    it = iter(iterator)
    with pytest.raises(StopIteration):
        next(it)

test with elements - Run Test

import pytest

def test_with_elements():
    iterator = ListIterator(['a', 'b', 'c'])
    it = iter(iterator)

    assert next(it) == 'a'
    assert next(it) == 'b'
    assert next(it) == 'c'

    with pytest.raises(StopIteration):
        next(it)

    it = iter(iterator)

    assert next(it) == 'a'
    assert next(it) == 'b'
    assert next(it) == 'c'

    with pytest.raises(StopIteration):
        next(it)
class ListIterable(object): def __next__(self): pass class ListIterator(object): def __iter__(self): pass # iterator = ListIterator([3, 2, 1]) # for elem in iterator: # print(elem) # print("====================") # for elem in iterator: # print(elem)