Level 1 Base class and list iterator
You are building iterators that can be paused and resumed: a job iterates for a while, saves its position as plain data, and later (maybe in a different process) a fresh iterator over the same data picks up exactly where it stopped.
Part A — the contract. Write an abstract base class ResumableIterator (use abc.ABC) with:
__iter__()returningself(implemented in the base class),- abstract
__next__(),get_state() -> dictandset_state(state: dict) -> None.
The base class itself, and any subclass that leaves one of the abstract methods out, must be impossible to instantiate (TypeError).
Part B — ResumableListIterator(items), a subclass that walks a Python list.
Rules for states (they apply to every iterator in this problem):
get_state()returns a new dict built only from JSON types (dict, list, str, int, float, bool, None). It must survivejson.loads(json.dumps(state)). Later calls tonextmust not change a dict you already returned.- A state is small: it stores positions and counts, never the items. Its JSON must stay under 200 characters no matter how big the data is.
get_state()never moves the iterator; calling it many times in a row is fine.set_state(state)on any iterator of the same class over the same data restores the position, including the "finished" position.set_stateraisesValueError(notKeyError/TypeError) and leaves the position unchanged when the state is unusable: malformed or missing fields, an index out of range, a state produced by a different iterator class, or a state saved over a list of a different length. The tests validate every field your state contains: they remove each field in turn, and set each integer field to values such as-1, an out-of-range10**6,"3"orNone, and expectValueErrorevery time. So don't add fields you don't check. Tip: store a"kind"tag and the data length in every state.
it = ResumableListIterator(["a", "b", "c", "d"])
next(it), next(it) # "a", "b"
saved = it.get_state()
next(it) # "c"
it.set_state(saved)
list(it) # ["c", "d"]
fresh = ResumableListIterator(["a", "b", "c", "d"])
fresh.set_state(saved)
next(fresh) # "c"
ResumableListIterator([1, 2]).set_state(saved) # ValueError: different length
An empty list stops immediately. next after the end keeps raising StopIteration.