A list comprehension builds a new list in one line. The shape is [expr for x in iterable if cond] — transform each item with expr, optionally keep only the ones that pass cond.
Where you meet it
- Reshaping data: square every number, strip every string, pull one field out of each record.
- Filtering: keep the positives, drop the empties, select the matches.
- Its siblings —
{k: v for ...}(dict) and{x for ...}(set) — build the other collections the same way.
What it does
It walks the iterable left to right, runs expr on each item, and collects the results into a brand-new list. The source is left untouched. The if clause is a gate: items that fail the test never reach the output.
It's map and filter fused into one line — reach for it to build a list, never to run side effects.
How it works
A comprehension is map and filter fused into one expression: [f(x) for x in xs if keep(x)] maps f over the items that keep lets through. It is exactly equivalent to the explicit loop:
result = []
for x in xs:
if keep(x):
result.append(f(x))
# same thing, one line:
result = [f(x) for x in xs if keep(x)]
Swap the brackets and you get the other comprehensions:
squares = {x: x*x for x in range(5)} # dict comprehension
distinct = {c for c in 'banana'} # set comprehension → {'b', 'a', 'n'}
Watch out
- Nested comprehensions read fast going wrong —
[y for row in m for y in row]is fine, but past two clauses an ordinary loop is kinder to the next reader. - Don't use one for pure side effects (printing, writing files). If you don't want the list, write a plain
forloop — building a list ofNones is wasteful and misleading. - For large or streamed data, a generator expression
(expr for x in xs)uses round brackets and yields lazily, instead of materialising the whole list in memory.
Go deeper
Eine List Comprehension baut eine neue Liste in einer Zeile. Die Form ist [expr for x in iterable if cond] — jedes Element mit expr transformieren, optional nur die behalten, die cond bestehen.
Wo es vorkommt
- Daten umformen: jede Zahl quadrieren, jeden String trimmen, ein Feld aus jedem Datensatz ziehen.
- Filtern: die Positiven behalten, die Leeren verwerfen, die Treffer auswählen.
- Die Geschwister —
{k: v for ...}(Dict) und{x for ...}(Set) — bauen die anderen Collections genauso.
Was es tut
Es durchläuft das Iterable von links nach rechts, führt expr auf jedem Element aus und sammelt die Ergebnisse in einer brandneuen Liste. Die Quelle bleibt unberührt. Die if-Klausel ist ein Tor: Elemente, die den Test nicht bestehen, erreichen die Ausgabe nie.
Sie verschmilzt map und filter zu einer Zeile — greif dazu, um eine Liste zu bauen, nie für Seiteneffekte.
Wie es funktioniert
Eine Comprehension verschmilzt map und filter zu einem Ausdruck: [f(x) for x in xs if keep(x)] mappt f über die Elemente, die keep durchlässt. Sie ist exakt äquivalent zur expliziten Schleife:
result = []
for x in xs:
if keep(x):
result.append(f(x))
# dasselbe, eine Zeile:
result = [f(x) for x in xs if keep(x)]
Klammern tauschen, und du bekommst die anderen Comprehensions:
squares = {x: x*x for x in range(5)} # Dict Comprehension
distinct = {c for c in 'banana'} # Set Comprehension → {'b', 'a', 'n'}
Worauf achten
- Verschachtelte Comprehensions werden schnell unleserlich —
[y for row in m for y in row]geht noch, aber jenseits von zwei Klauseln ist eine normale Schleife freundlicher zum nächsten Leser. - Nicht für reine Seiteneffekte verwenden (Ausgeben, Dateien schreiben). Brauchst du die Liste nicht, schreib eine schlichte
for-Schleife — eine Liste ausNones zu bauen ist verschwenderisch und irreführend. - Bei großen oder gestreamten Daten nutzt ein Generator-Ausdruck
(expr for x in xs)runde Klammern und liefert faul (lazy), statt die ganze Liste im Speicher zu materialisieren.