Slicing iterators with islice

itertools · Essentials · 7 min

Generators, files and infinite iterators don't support [a:b], but you still need 'the first 10' or 'skip the header'.

Iterators can't be indexed or sliced with [start:stop]. islice provides the same semantics lazily:

  • islice(it, stop) the first stop items
  • islice(it, start, stop) items from index start up to stop
  • islice(it, start, stop, step) with a step
  • stop=None means "to the end": islice(it, 1, None) skips the first item

Negative values are not allowed, because an iterator doesn't know its length.

islice consumes the underlying iterator as it goes. Skipping 1,000 items means producing and discarding them, so it's O(start), not O(1) like a list slice. And the original iterator is advanced: after list(islice(it, 3)), the next item of it is the fourth.

That last property is useful. Reading a file, next(f) or islice(f, 1, None) skips a header line. Taking repeated islice(it, n) chunks from one iterator is how batching worked before itertools.batched.

Common combos:

  • islice(count(), 5) the first five numbers
  • next(islice(it, n, None), default) the n-th item (the nth recipe)
  • list(islice(sorted_generator, 10)) a top-10 preview without consuming everything

Example

from itertools import count, islice

def squares():
    for n in count():
        yield n * n

print(list(islice(squares(), 5)))           # [0, 1, 4, 9, 16]
print(list(islice(squares(), 2, 8, 2)))     # [4, 16, 36]

it = iter(range(10))
print(list(islice(it, 3)))                  # [0, 1, 2]
print(next(it))                             # 3  -- original advanced

lines = iter(["id,name", "1,ann", "2,bob"])
for row in islice(lines, 1, None):          # skip header
    print(row)
# 1,ann
# 2,bob
print(next(islice(squares(), 10, None)))    # 100

Remember

  • islice(it, start, stop, step) slices any iterator lazily
  • Skipping costs O(start) and advances the original iterator
  • No negative indices: iterators have no known length

Watch out for

  • Calling islice(it, -5, None) to get the last items; use collections.deque(it, maxlen=5) instead.

Check yourself

  1. it = iter('abcdef'); list(islice(it, 2)); what is next(it)?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/itertools.html#itertools.islice