2.30. Comprehensions

En comprehension bygger en ny lista, mängd, dict eller generator från en befintlig iterabel, i ett enda uttryck. Den ersätter det vanliga mönstret att börja med en tom behållare och lägga till i en loop.

2.30.1. List comprehensions

squares = [x * x for x in range(5)]
print(squares)

Utdata:

[0, 1, 4, 9, 16]

Samma loop utskriven:

squares = []
for x in range(5):
    squares.append(x * x)

Comprehension-formen är ett uttryck som bygger listan på plats. Det finns inget squares = [] och inget .append – resultatet är värdet av denna comprehension.

Uttrycket "[f(x) for x in xs if cond]" kommenterat: det inledande uttrycket är resultatet, for-satsen namnger loopvariabeln, if-satsen filtrerar vilka element som behålls.

Det inledande uttrycket producerar varje element; for-satsen namnger loopvariabeln; en valfri if filtrerar bort element.

2.30.2. Filtrering med if

En valfri if-sats behåller endast de element som matchar:

evens = [x for x in range(10) if x % 2 == 0]
print(evens)

Utdata:

[0, 2, 4, 6, 8]

Filtret körs före det inledande uttrycket – x % 2 == 0 kontrolleras först; endast matchande värden når x för utdatan.

2.30.3. Comprehensions för dict och mängd

Samma form fungerar med dict- och mängdlitteraler.

En dict comprehension har ett key: value-par före for:

squares = {x: x * x for x in range(5)}
print(squares)

Utdata:

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

En set comprehension använder klamrar och ett enda uttryck:

unique_lengths = {len(w) for w in ["a", "bb", "c", "bb"]}
print(unique_lengths)

Utdata:

{1, 2}

2.30.4. Generatoruttryck

Vanliga parenteser producerar ett generatoruttryck i stället för en lista. Värdena beräknas ett i taget, vid behov:

total = sum(x * x for x in range(1000))

Ingen miljonelementslista byggs någonsin. Värdena flödar ett och ett in i sum(), som adderar dem och kasserar varje värde efter hand.

Generatoruttryck är rätt val när man matar in värden i en reducerande funktion (sum(), max(), any(), all()) eller någon annan kod som konsumerar en iterator – de sparar det minne som den motsvarande listan skulle ha använt.

2.30.5. När man inte ska använda en comprehension

Comprehensions är koncisa men inte alltid tydligare. Ta till en vanlig for-loop när:

  • Kroppen behöver mer än en sats (en comprehension rymmer exakt ett uttryck).

  • Kroppen har sidoeffekter (utskrift, skrivning till en fil) – comprehensions är till för att bygga en samling, inte för att utföra åtgärder.

  • Filtret eller transformationen har så många delar att denna comprehension inte längre läses från vänster till höger.