Tanquem el mòdul amb la construcció més característica de Python. A les lliçons anteriors hauràs notat un patró repetit: crear una llista nova recorrent-ne una altra — els preus del catàleg amb IVA, els títols en majúscules per a les etiquetes, els llibres que encara tenen estoc. Aquest patró de tres o quatre línies (crear llista buida, recórrer, transformar o filtrar, afegir) és tan freqüent que Python li dedica una sintaxi pròpia: les comprensions de llistes (list comprehensions), que el condensen en una sola línia llegible. Dominar quan usar-les — i quan no — és un dels trets d'identitat del codi "pythònic".

Contingut

  1. El patró que comprimirem
  2. Sintaxi bàsica: [expressio for element in iterable]
  3. Filtrar amb if al final
  4. Transformar amb if/else a l'expressió
  5. Comprensions imbricades (amb moderació)
  6. Comprensió vs. bucle: comparació directa
  7. Quan NO usar una comprensió
  8. Un cop d'ull a les comprensions de diccionaris i conjunts

El patró que comprimirem

L'Anna vol la llista de preus del catàleg amb l'IVA de llibres inclòs. Amb el que saps de la lliçó de bucles, ho faries així:

IVA_LLIBRES = 0.04
preus = [12.50, 9.95, 15.90]

preus_amb_iva = []                        # 1. llista buida de partida
for preu in preus:                        # 2. recorrer l'original
    preus_amb_iva.append(preu * (1 + IVA_LLIBRES))   # 3. transformar i afegir

print(preus_amb_iva)

Sortida:

[13.0, 10.348, 16.536]

Apareix aquí append(), el mètode que afegeix un element al final d'una llista — l'estudiarem amb detall al mòdul 4; per ara n'hi ha prou amb aquesta idea. El patró complet té sempre les mateixes tres peces: llista buida → bucle → append d'una transformació. Python permet expressar exactament això en una línia.

Sintaxi bàsica: [expressio for element in iterable]

La mateixa llista de preus amb IVA, com a comprensió:

IVA_LLIBRES = 0.04
preus = [12.50, 9.95, 15.90]

preus_amb_iva = [preu * (1 + IVA_LLIBRES) for preu in preus]

print(preus_amb_iva)   # [13.0, 10.348, 16.536]

Anatomia de la línia, de dins cap enfora:

Peça A l'exemple Paper
for element in iterable for preu in preus El mateix encapçalament de bucle que ja coneixes
expressio preu * (1 + IVA_LLIBRES) Què es guarda a la llista nova per cada element
[ ... ] els claudàtors Indiquen "construeix una llista amb tot això"

Es llegeix de manera gairebé natural: "una llista amb preu * (1 + IVA) per a cada preu dins de preus". L'ordre d'escriptura sorprèn al principi (l'expressió va abans del for), però reflecteix el que t'interessa: primer què obtens, després d'on surt.

Més exemples ràpids amb material de Papyrus:

titols = ["L'Odissea", "Hamlet", "El Quixot"]

# Titols en majuscules per a les etiquetes de les prestatgeries
etiquetes = [titol.upper() for titol in titols]
# ["L'ODISSEA", 'HAMLET', 'EL QUIXOT']

# Longitud de cada titol (per calcular l'ample de la taula del menu)
longituds = [len(titol) for titol in titols]
# [9, 6, 9]

# Els primers 5 numeros de tiquet del dia
tiquets = [f"T-{n:03d}" for n in range(1, 6)]
# ['T-001', 'T-002', 'T-003', 'T-004', 'T-005']

(upper() passa una cadena a majúscules; com lower() a la lliçó anterior, és un mètode de str que veurem a fons al mòdul 4.) Observa el tercer exemple: l'iterable pot ser un range, una cadena, una altra llista... qualsevol cosa recorrible amb for. I l'expressió pot ser tan simple com el mateix element ([x for x in dades], que copia la llista) o tan elaborada com una f-string.

Filtrar amb if al final

Segona peça: de vegades no vols transformar tots els elements, sinó quedar-te només amb alguns. Afegeix un if després del for:

[expressio for element in iterable if condicio]

Només els elements que compleixin la condició passen a la llista nova. El clàssic de Papyrus: quins llibres tenen estoc?

titols = ["L'Odissea", "Hamlet", "El Quixot", "Faust"]
estocs = [4, 6, 8, 0]

disponibles = [titols[i] for i in range(len(titols)) if estocs[i] > 0]
print(disponibles)   # ["L'Odissea", 'Hamlet', 'El Quixot']

I combinant transformació + filtre en una sola comprensió — preus amb IVA, però només dels llibres que costen menys de 15 €:

IVA_LLIBRES = 0.04
preus = [12.50, 9.95, 15.90]

economics_amb_iva = [p * (1 + IVA_LLIBRES) for p in preus if p < 15]
print(economics_amb_iva)   # [13.0, 10.348]

Es llegeix: "el preu amb IVA, per a cada p dins de preus, si p < 15". El filtre s'aplica primer (entra aquest element?) i l'expressió després (què en guardo?). El Quixot (15.90) no supera el filtre, així que ni tan sols se'n calcula l'IVA.

A l'if pots usar tot el de la lliçó 02-01: condicions compostes (if p < 15 and p > 10), truthiness (if titol per descartar cadenes buides), not...

respostes = ["Hamlet", "", "Faust", ""]

# Netejar entrades buides d'un formulari de comandes
comandes_valides = [r for r in respostes if r]
print(comandes_valides)   # ['Hamlet', 'Faust']

Transformar amb if/else a l'expressió

Compte, aquest cas es confon molt amb l'anterior. L'if al final filtra (alguns elements no entren). Però si vols que tots els elements entrin, triant entre dos valors segons una condició, el que necessites és l'operador ternari de la lliçó 02-01, col·locat a l'expressió:

[valor_si_true if condicio else valor_si_false for element in iterable]

Exemple: el llistat del menú de Papyrus ha de mostrar tots els títols, marcant els esgotats.

titols = ["L'Odissea", "Hamlet", "El Quixot", "Faust"]
estocs = [4, 6, 8, 0]

llistat = [
    titols[i] if estocs[i] > 0 else f"{titols[i]} (ESGOTAT)"
    for i in range(len(titols))
]
print(llistat)
# ["L'Odissea", 'Hamlet', 'El Quixot', 'Faust (ESGOTAT)']

Les dues posicions de l'if, cara a cara:

Forma Posició de l'if else? Efecte Mida de la llista resultat
[expr for x in dades if cond] Després del for No l'admet Filtra elements ≤ que l'original
[a if cond else b for x in dades] A l'expressió (ternari) Obligatori Tria el valor de cada element Igual que l'original

Truc mnemotècnic: if sense else al final = porter (decideix qui entra); if amb else al principi = transformador (decideix en què es converteix cadascun). I sí, es poden combinar tots dos en una mateixa comprensió, tot i que la llegibilitat comença a ressentir-se'n:

# Amb descompte de soci els barats, amb IVA tots, i fora els esgotats
DESCOMPTE_SOCI = 0.05
preus = [12.50, 9.95, 15.90, 21.00]
estocs = [4, 6, 8, 0]

finals = [
    round(p * (1 - DESCOMPTE_SOCI), 2) if p < 15 else round(p, 2)
    for i, p in enumerate(preus)
    if estocs[i] > 0
]
print(finals)   # [11.88, 9.45, 15.9]

Fixa't també que una comprensió llarga es pot (i s'ha de) partir en diverses línies, alineant el for i l'if — continua sent una sola expressió entre claudàtors. I que enumerate() funciona dins de les comprensions igual que als bucles normals.

Comprensions imbricades (amb moderació)

Igual que els bucles s'imbriquen, una comprensió admet diversos for seguits. Equival a bucles imbricats llegits d'esquerra a dreta (el primer for és el bucle exterior):

# Totes les combinacions format-idioma que Papyrus pot demanar al distribuidor
formats = ["tapa dura", "butxaca"]
idiomes = ["ca", "en"]

combinacions = [f"{format_llibre} ({idioma})" for format_llibre in formats for idioma in idiomes]
print(combinacions)
# ['tapa dura (ca)', 'tapa dura (en)', 'butxaca (ca)', 'butxaca (en)']

El seu equivalent amb bucles, perquè vegis la correspondència exacta:

combinacions = []
for format_llibre in formats:       # primer for de la comprensio
    for idioma in idiomes:          # segon for de la comprensio
        combinacions.append(f"{format_llibre} ({idioma})")

Un altre ús de la imbricació és una comprensió dins d'una altra, per exemple per generar una estructura tabular (una llista de llistes):

# Graella d'ubicacions: 2 passadissos x 3 estants
ubicacions = [[f"P{p}-E{e}" for e in range(1, 4)] for p in range(1, 3)]
print(ubicacions)
# [['P1-E1', 'P1-E2', 'P1-E3'], ['P2-E1', 'P2-E2', 'P2-E3']]

Advertència sincera: dos for en una comprensió és el límit raonable. Tres o més, o imbricacions amb filtres i ternaris alhora, produeixen línies que ningú (ni tu d'aquí a un mes) no desxifra a la primera. En aquests casos, els bucles imbricats clàssics de la lliçó 02-02 són la millor eina. Comprimir no és l'objectiu; comunicar, sí.

Comprensió vs. bucle: comparació directa

Posem les dues versions costat a costat amb l'exemple complet de Papyrus — preus finals per a en Lluís (soci) dels llibres disponibles:

DESCOMPTE_SOCI = 0.05
IVA_LLIBRES = 0.04
preus = [12.50, 9.95, 15.90, 21.00]
estocs = [4, 6, 8, 0]

# ---- Versio bucle: 5 linies ----
preus_lluis = []
for i, p in enumerate(preus):
    if estocs[i] > 0:
        final = p * (1 - DESCOMPTE_SOCI) * (1 + IVA_LLIBRES)
        preus_lluis.append(round(final, 2))

# ---- Versio comprensio: 1 expressio ----
preus_lluis = [
    round(p * (1 - DESCOMPTE_SOCI) * (1 + IVA_LLIBRES), 2)
    for i, p in enumerate(preus)
    if estocs[i] > 0
]

print(preus_lluis)   # [12.35, 9.83, 15.71] en tots dos casos

Què guanya cada versió?

Criteri Bucle for clàssic Comprensió
Línies de codi Més Menys
Es llegeix com Recepta pas a pas Declaració: "vull aquesta llista"
Passos intermedis (prints de depuració, diverses operacions) Fàcils d'afegir No hi caben
break/continue Disponibles No existeixen dins d'una comprensió
Efectes col·laterals (imprimir, modificar altres variables) Naturals Contraindicats
Velocitat Bona Lleugerament més gran (l'append està optimitzat internament)

L'avantatge real de la comprensió no és estalviar tecles: és declarar la intenció. [t.upper() for t in titols] diu "una llista amb els títols en majúscules" d'un cop d'ull; el bucle equivalent obliga a llegir tres línies per deduir el mateix. Per això, per al patró transformar/filtrar una col·lecció en una llista nova, la comprensió és la forma preferida a la comunitat Python.

Quan NO usar una comprensió

Tan important com saber usar-les és saber contenir-se. Senyals que toca tornar al bucle clàssic:

  • No estàs construint una llista. Si l'objectiu és imprimir, acumular un total o demanar input(), usa un bucle. Escriure [print(t) for t in titols] funciona, però crea una llista inútil de None i confon el lector: les comprensions són per produir dades, no per fer coses.
  • La línia no hi cap o no s'entén. Si necessites més de dues o tres peces (dos for, un filtre i un ternari, per exemple) o superes amb claredat els 79-99 caràcters de PEP 8 fins i tot partint-la, un bucle amb noms intermedis serà més clar.
  • Necessites parar a mitges o saltar elements amb lògica complexa. No hi ha break ni continue en una comprensió; si els trobes a faltar, és un bucle.
  • Hi ha diversos passos dependents. Calcular un valor, comprovar-lo, ajustar-lo i després guardar-lo són diverses sentències; encabir-les en una expressió sol requerir trucs il·legibles.
  • Estàs depurant. Un bucle admet print() intermedis per inspeccionar valors; una comprensió, no. De vegades convé "desplegar" temporalment una comprensió a bucle per investigar un problema i tornar-la a plegar després.

Regla final: escriu la comprensió, rellegeix-la com si la veiés una altra persona i, si has de pensar més d'un parell de segons per entendre-la, converteix-la en bucle. Ningú no ha retret mai un bucle clar.

Un cop d'ull a les comprensions de diccionaris i conjunts

La mateixa idea funciona amb altres estructures de dades de Python que estudiaràs al mòdul 4. Només com a aperitiu:

titols = ["L'Odissea", "Hamlet", "El Quixot"]
preus = [12.50, 9.95, 15.90]

# Comprensio de DICCIONARI (claus i dos punts): titol -> preu
tarifa = {titols[i]: preus[i] for i in range(len(titols))}
# {"L'Odissea": 12.5, 'Hamlet': 9.95, 'El Quixot': 15.9}

# Comprensio de CONJUNT (claus sense dos punts): inicials uniques
inicials = {titol[0] for titol in titols}
# {'L', 'H', 'E'}

Els diccionaris (parelles clau-valor) i els conjunts (col·leccions sense duplicats) mereixen les seves pròpies lliçons; quan hi arribem al mòdul 4, les seves comprensions et resultaran familiars: són exactament aquesta sintaxi amb {} en lloc de []. De moment, queda't amb la idea que el patró que has après avui és general.

Errors Comuns i Consells

  • Confondre l'if-filtre amb l'if/else-ternari: [x for x in dades if cond] filtra; [a if cond else b for x in dades] transforma. Escriure [x for x in dades if cond else y] és SyntaxError: l'if final no admet else.
  • Usar comprensions pels seus efectes ([print(x) for x in ...]): tècnicament vàlid, estilísticament incorrecte. Si no fas servir la llista resultant, és un bucle.
  • Fer ombra a variables: la variable de la comprensió és local a ella, però si li poses el mateix nom que una altra variable del programa (preu = 100 i després [preu for preu in preus]), el codi es torna confús. Usa noms diferents i descriptius.
  • Imbricar de més: dos for és el màxim còmode. Si dubtes, desplega a bucles.
  • Oblidar que produeix una llista nova: la comprensió no modifica la llista original; preus continua intacta després de [p * 2 for p in preus]. Si vols conservar el resultat, assigna'l a una variable.
  • Consell: quan una comprensió s'allargui, parteix-la en diverses línies dins dels claudàtors (expressió / for / if, una peça per línia). Python ho permet i la llegibilitat millora moltíssim.
  • Consell: en llegir una comprensió aliena, comença pel for (què recorre?), segueix per l'if (què deixa passar?) i acaba per l'expressió (què construeix?). És l'ordre en què s'executa.

Exercicis

Exercici 1: PVP del catàleg

Donada preus = [12.50, 9.95, 15.90] i la constant IVA_LLIBRES = 0.04, crea amb una comprensió la llista pvp amb cada preu amb IVA arrodonit a 2 decimals (usa round(valor, 2)). Després, amb una altra comprensió, crea pvp_soci aplicant a més DESCOMPTE_SOCI = 0.05 sobre el preu base, només per a preus base inferiors a 15 € (els altres no han d'aparèixer a la llista).

Exercici 2: etiquetes de l'aparador

Donades titols = ["L'Odissea", "Hamlet", "El Quixot", "Faust"] i estocs = [4, 6, 8, 0], crea amb una sola comprensió la llista d'etiquetes de l'aparador: tots els títols en majúscules, i els que estiguin esgotats amb el sufix " - PROPERAMENT". Resultat esperat: ["L'ODISSEA", 'HAMLET', 'EL QUIXOT', 'FAUST - PROPERAMENT'].

Exercici 3: de comprensió a bucle (i criteri)

Aquesta comprensió funciona, però és difícil de llegir:

r = [t.upper() if s > 3 else t.lower() for t, s in zip(titols, estocs) if len(t) > 6 and s != 1]

(a) Reescriu-la com a bucle for clàssic amb noms de variables descriptius. (b) Explica en una frase per què en aquest cas el bucle és preferible. Nota: zip() emparella dues llistes element a element — s'estudia al mòdul 3; per a aquest exercici en tens prou sabent que for t, s in zip(titols, estocs) recorre títol i estoc alhora.

Solucions

Solució 1:

IVA_LLIBRES = 0.04
DESCOMPTE_SOCI = 0.05
preus = [12.50, 9.95, 15.90]

pvp = [round(p * (1 + IVA_LLIBRES), 2) for p in preus]
print(pvp)          # [13.0, 10.35, 16.54]

pvp_soci = [
    round(p * (1 - DESCOMPTE_SOCI) * (1 + IVA_LLIBRES), 2)
    for p in preus
    if p < 15
]
print(pvp_soci)     # [12.35, 9.83]

La primera és una transformació pura (mateixa longitud que l'original). La segona combina filtre (if p < 15, que descarta El Quixot) i transformació (descompte sobre la base i després IVA, el mateix ordre de càlcul que vam usar a la lliçó 02-01).

Solució 2:

titols = ["L'Odissea", "Hamlet", "El Quixot", "Faust"]
estocs = [4, 6, 8, 0]

etiquetes = [
    titols[i].upper() if estocs[i] > 0 else titols[i].upper() + " - PROPERAMENT"
    for i in range(len(titols))
]
print(etiquetes)
# ["L'ODISSEA", 'HAMLET', 'EL QUIXOT', 'FAUST - PROPERAMENT']

Aquí l'if/else va a l'expressió (ternari) perquè tots els títols han d'aparèixer: no filtrem, triem el format de cadascun. Versió encara més neta, aplicant el sufix amb el ternari: [titols[i].upper() + ("" if estocs[i] > 0 else " - PROPERAMENT") for i in range(len(titols))].

Solució 3:

titols = ["L'Odissea", "Hamlet", "El Quixot", "Faust"]
estocs = [4, 6, 8, 0]

resultat = []
for titol, estoc in zip(titols, estocs):
    if len(titol) > 6 and estoc != 1:
        if estoc > 3:
            resultat.append(titol.upper())
        else:
            resultat.append(titol.lower())

print(resultat)   # ["L'ODISSEA", 'EL QUIXOT']

Amb aquestes dades, Hamlet (6 lletres) i Faust (5 lletres) no superen el filtre len(titol) > 6, i els dos títols llargs tenen estoc alt, així que tots dos surten en majúscules. (b) El bucle és preferible perquè la comprensió original acumula quatre peces (ternari + for + zip + filtre compost) en una línia: el lector ha de desxifrar alhora què filtra i què transforma, mentre que el bucle separa cada decisió a la seva pròpia línia amb noms clars. És exactament el criteri de "quan NO usar una comprensió": si costa més d'un parell de segons entendre-la, desplega-la.

Conclusió

Amb les comprensions de llistes has tancat el cercle d'aquest mòdul: [expressio for x in iterable if condicio] reuneix en una sola línia declarativa el que has après per separat — la transformació d'un bucle for, el filtre d'un if i l'elecció d'un ternari. Saps filtrar (if al final), transformar (if/else a l'expressió), imbricar amb prudència i, sobretot, reconèixer quan un bucle clàssic comunica millor. També has vist que la mateixa sintaxi s'estén a diccionaris i conjunts, un avançament del mòdul 4.

El mòdul 2 acaba aquí, i Papyrus ho nota: els seus scripts ja decideixen (if/elif/else), repeteixen (for, while), busquen i paren (break, else de bucle), conversen mitjançant menu.py (while True + match) i generen llistes de preus i etiquetes en una línia. Però tot aquest codi viu solt, repetit d'script en script: la cerca del menú, el càlcul del preu de soci, la validació d'entrades... Cada millora obliga a tocar diversos llocs. La solució és empaquetar cada tasca amb nom propi i reutilitzar-la on calgui: això són les funcions, protagonistes del mòdul 3, on reorganitzarem el menú de Papyrus peça a peça i descobriràs que ja fas servir funcions (print, len, enumerate...) des del primer dia.

Curs de Programació en Python

Mòdul 1: Introducció a Python

Mòdul 2: Estructures de Control

Mòdul 3: Funcions i Mòduls

Mòdul 4: Estructures de Dades

Mòdul 5: Programació Orientada a Objectes

Mòdul 6: Gestió de Fitxers

Mòdul 7: Gestió d'Errors i Excepcions

Mòdul 8: Temes Avançats

Mòdul 9: Proves i Depuració

Mòdul 10: Desenvolupament Web amb Python

Mòdul 11: Ciència de Dades amb Python

Mòdul 12: Projecte Final

© Copyright 2026. Tots els drets reservats