Python's for loop works on anything that follows the iterator protocol: __iter__ returns the iterator itself, and __next__ returns the next item or raises StopIteration when there are none left. Write one by hand.
Implement class Chunks:
Chunks(iterable, size)wraps any iterable (a list, a string, a generator, even an infinite one) and yields its items in lists ofsize, in order.- The last chunk may be shorter. Never yield an empty chunk.
sizemust be a positive integer; otherwise the constructor raisesValueError.iter(chunks)returns the object itself, and once it's exhausted every furthernext()keeps raisingStopIteration.- It must be lazy: pull only as many items from the source as the chunk you're building needs. Don't turn the whole input into a list up front, because it may never end.
list(Chunks([1, 2, 3, 4, 5], 2)) # [[1, 2], [3, 4], [5]]
list(Chunks("abc", 5)) # [["a", "b", "c"]]
list(Chunks([], 3)) # []
import itertools
c = Chunks(itertools.count(), 3)
next(c) # [0, 1, 2]
next(c) # [3, 4, 5]
Write it as a class with __iter__ and __next__ (not a generator function); that's the skill being practised.
Show hint
keep iter(iterable) in an attribute, and in __next__ call next() on it up to size times, stopping early when it runs dry; an empty chunk means you're done, so raise StopIteration.