Python Iterators and Generators Quiz: itertools Practice Test

Test yourself with 12 questions and three programs on Python iterators, generators, generator expressions, itertools, functools and lazy pipelines.

  • Course: Python study plan
  • Module: Iterators, generators and itertools
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 25 min
  • Runtime: CPython 3.11

Checkpoint — Iterators, generators and itertools is the checkpoint that closes the Iterators, generators and itertools module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers the whole module: the iteration protocol with iter, next and StopIteration, generators with yield, yield from and laziness, generator expressions and the short-circuit consumers, the itertools toolkit with groupby's consecutive-run rule and the combinatoric generators, functools and operator, and the design of lazy pipelines.

How it works. Twelve questions and three programs. You need 70% on the questions and every program accepted to clear the module. You can retake it as often as you like; your best score counts.

Before you start, make sure you can answer these from memory:

  • What is the difference between an iterable and an iterator, and which one is zip(a, b)?
  • What happens the first time a generator function is called, and when does its body run?
  • Why is sum(x for x in xs) preferable to sum([x for x in xs]), and when is a list comprehension still right?
  • What does groupby do on unsorted input?
  • What are product, permutations and combinations, and how do their sizes grow?
  • What does @cache require of a function?
  • In a pipeline, which stage should handle a malformed record, and why?

The three programs are a run-length codec built on groupby, a subset-sum search over combinations that stops at the first hit, and a log pipeline of generator stages that parses, filters and aggregates in one pass.

Common questions

What is the difference between an iterable and an iterator, and which one is zip(a, b)?

An iterable is anything iter() accepts and can hand out fresh iterators, like a list or a range; an iterator produces the values through __next__ and is one-shot. zip(a, b) returns an iterator, so a second pass over the same zip object yields nothing.

What happens when a generator function is called?

None of its body runs: the call returns a generator object. The body runs only when a value is requested by next() or a loop, executing to the next yield and suspending there, so an error inside it surfaces at that next() rather than at the call.

What does @cache require of a function?

The function must be pure, meaning the same arguments always give the same result with no side effects that matter, and every argument must be hashable, because the arguments form the cache key. A list argument raises TypeError; pass a tuple instead.

Exercises

Run-length codec with groupby

Each line is E <text> or D <code>. Encode with itertools.groupby — each run becomes the character followed by its count (aaabcc → a3b1c2). Decode by scanning the code: a character followed by one or more digits (a generator that yields the expanded characters, joined at the end). Text after the command is taken literally.

Input: lines. Output: one line per input line (an empty result prints (empty)).

E aaabcc
D a3b1c2

prints

a3b1c2
aaabcc

Subset sum, first hit

Read a target and a line of positive integers. Search the combinations of indexes by increasing size (1, 2, …, all) with itertools.combinations, in the order combinations produces them, and stop at the first combination whose values sum to the target — using next over a generator expression chained across sizes with itertools.chain.from_iterable. Print the chosen values or none.

Input: the target, then a line of integers. Output: found <values> or none.

9
2 7 5 4

prints

found 2 7

Log pipeline

Process log lines ip method path status size through generator stages: read_lines (strip, drop blank), parse (yield a tuple with status and size as ints; skip lines with the wrong field count or non-integer fields), only(method="GET"), and a single-pass summarise that returns status counts, path counts and total bytes. Print status <code>: <n> in ascending order, bytes <total>, and top <path> (most requests, ties alphabetical) or top none.

Input: lines. Output: the summary.

1.1.1.1 GET /a 200 100
1.1.1.2 POST /a 200 50
1.1.1.1 GET /b 404 0
bad line

prints

status 200: 1
status 404: 1
bytes 100
top /a

In this module: Iterators, generators and itertools

← Lazy pipelines — a worked log-processing example · Modules and imports — files, namespaces and sys.modules →