The itertools.chain.from_iterable and itertools.chain should include a note referring to PEP 798 alternatives

Doc note cross-referencing PEP 798 from itertools.chain / chain.from_iterable

Now that PEP 798 (Unpacking in Comprehensions) is accepted and slated for 3.15, I’d like to propose a small, docs-only addition: a short note in the itertools.chain and itertools.chain.from_iterable entries pointing readers to the new unpacking-in-comprehension syntax as an inline alternative for flattening.

Why

chain.from_iterable is effectively the textbook motivating example for PEP 798 — the PEP’s own “Replacing from_iterable and Friends” section rewrites several stdlib call sites in terms of (*it for it in its). Readers who land on the itertools docs reaching for from_iterable to flatten an iterable of iterables are exactly the audience who’d benefit from knowing the inline form now exists, but nothing in the itertools docs currently signals it.

This is purely a discoverability nudge, not a redirect.

What I’m not proposing

  • No change to the “roughly equivalent” code. The reference equivalent uses yield from, and I think it should stay classic and version-agnostic. (Tangentially: the genexp form’s explicit-loop semantics — no .send()/.throw()/.close() delegation — actually model the C object slightly more faithfully than yield from does, but that’s far too subtle to belong in the reference snippet.)
  • No deprecation, no recommendation. chain / from_iterable remain the right tool as first-class callables (e.g. map(chain.from_iterable, ...)), in code targeting < 3.15, and in hot paths where the C implementation wins. The PEP explicitly notes that replacing from_iterable is “not always the right choice,” so the note should read as a pointer, not advice.

Proposed wording (rough — bikeshed welcome)

For chain.from_iterable (the primary target):

Note: Since Python 3.15, a list, set, or generator can be built inline from an arbitrary number of iterables using unpacking in a comprehension or generator expression (see PEP 798), for example (*it for it in iterables) or [*it for it in iterables]. This is often more readable for simple flattening; chain.from_iterable remains useful as a first-class callable and in code targeting earlier versions.

For chain, I’d keep it lighter, because the fixed-arity case chain(a, b, c) already has a PEP 448 inline form [*a, *b, *c]. The PEP 798 form is the natural inline alternative specifically when one would otherwise write chain(*iterables) over an arbitrary sequence — so a one-line cross-reference to the from_iterable note (or to PEP 798) is probably enough rather than a duplicate block.

Open questions for discussion

  1. Is a See also / Note wanted here at all, or is this the kind of “every function could point at newer syntax” creep the docs try to avoid?
  2. Touch only from_iterable, or both entries?
  3. Phrasing of the version marker — a .. versionchanged:: 3.15 feels wrong (the function didn’t change), so probably just an inline “Since 3.15” in the note text.

Happy to put up a docs PR if there’s appetite. Mostly want to gauge interest and settle scope/wording first.

13 Likes

I like the whole proposal.

A “see also” would be reasonable. This isn’t really about chain. It is sort of a promotion / advertisement of a new language feature.

This has been done in gh-152397: Provide a cross-reference to PEP 798 unpacking syntax by rhettinger · Pull Request #152454 · python/cpython · GitHub, thanks for the suggestion!

3 Likes