Les dues lliçons anteriors van deixar un problema molt concret sobre la taula. La llista va resoldre el «moltes tasques», però per guardar els camps de cada tasca ens va obligar a mantenir cinc llistes paral·leles sincronitzades a mà: un pop oblidat i el llistat comença a mentir. El motiu de fons és que en una llista les dades s'identifiquen per posició, i la posició no significa res: tasca[1] no diu si l'1 és el responsable o la prioritat.

Aquesta lliçó presenta dues estructures que resolen problemes diferents i que gairebé sempre s'ensenyen juntes. El diccionari guarda cada dada amb el seu nom, de manera que tasca["responsable"] s'explica sola. El conjunt guarda elements únics sense ordre, i és l'eina correcta per a preguntes del tipus «hi és, això?» o «quines etiquetes diferents fem servir?». Al final, TascaFàcil farà el salt a la v0.9 i una tasca passarà a ser, per fi, una sola cosa.

Contingut

  1. Clau i valor: el problema que resol el diccionari
  2. Crear diccionaris i accedir als seus valors
  3. Afegir, modificar i esborrar
  4. Recórrer un diccionari
  5. update, setdefault i què pot ser una clau
  6. Diccionari per comprensió i recompte de freqüències
  7. Conjunts: elements únics i sense ordre
  8. Operacions entre conjunts
  9. Usos típics dels conjunts
  10. Llista, diccionari o conjunt: taula de decisió
  11. TascaFàcil v0.9: la tasca és un diccionari
  12. Errors comuns i consells
  13. Exercicis
  14. Conclusió

  1. Clau i valor: el problema que resol el diccionari

Un diccionari (tipus dict) és una col·lecció de parells clau → valor. La clau substitueix l'índex numèric: en comptes de recordar que el responsable és a la posició 1, el demanes pel seu nom.

tasca = {"titol": "Cartell fira del llibre", "responsable": "Marta",
         "prioritat": "alta", "dies": 3, "completada": False}
print(tasca["responsable"])     # Marta
print(len(tasca))               # 5  -> nombre de parells

Compara les dues maneres de guardar la mateixa tasca:

Llista Diccionari
S'hi accedeix per Posició: tasca[1] Nom: tasca["responsable"]
Es llegeix sol No: cal recordar l'ordre Sí
Afegir un camp nou Trenca tots els índexs posteriors Només afegeix una clau
Ordre dels elements Significatiu Irrellevant per a l'accés
Bon ús Moltes coses del mateix tipus Els camps diferents d'una cosa

Aquesta última fila és la regla de decisió: llista per a «molts», diccionari per a «un amb diversos camps». Els responsables de l'estudi són una llista (["Marta", "Luis", "Nuria"]); una tasca concreta és un diccionari. I quan vulguis moltes tasques, serà una llista de diccionaris, que és exactament 05-04.

  1. Crear diccionaris i accedir als seus valors

Hi ha dues maneres de crear-lo, i un diccionari buit s'escriu {}:

tasca = {"titol": "Menu Sole", "dies": 5}       # literal amb claus
altra = dict(titol="Menu Sole", dies=5)         # amb dict() i arguments per nom
buit = {}
print(tasca == altra)               # True -> son equivalents
print(tasca["titol"])               # Menu Sole
print(tasca["responsable"])         # KeyError: 'responsable'
print(tasca.get("responsable"))     # None  -> no falla
print(tasca.get("responsable", "sense assignar"))       # sense assignar

Per llegir un valor hi ha, per tant, dos camins, i triar bé és important:

Forma Si la clau existeix Si no existeix
d[clau] Retorna el valor KeyError i el programa s'atura
d.get(clau) Retorna el valor Retorna None
d.get(clau, defecte) Retorna el valor Retorna defecte

La regla pràctica: fes servir d[clau] quan la clau ha de ser-hi (si no hi és, és un error de programació i vols assabentar-te'n), i .get() quan la seva absència sigui una possibilitat normal. Per comprovar-ho explícitament hi ha l'operador in, que en un diccionari mira les claus i no els valors: "titol" in tasca és True, però "Menu Sole" in tasca és False perquè això és un valor.

  1. Afegir, modificar i esborrar

Afegir i modificar s'escriuen igual, i aquest és un dels paranys del tipus: si la clau no existeix, es crea; si existeix, se sobreescriu sense avisar.

tasca = {"titol": "Menu Sole", "dies": 5}
tasca["responsable"] = "Luis"       # la clau no existeix: s'afegeix
tasca["dies"] = 6                   # la clau existeix: se sobreescriu
del tasca["dies"]                   # esborra; KeyError si no existeix
valor = tasca.pop("responsable")    # esborra i retorna el valor
altre = tasca.pop("client", "cap")  # amb defecte: no falla si no hi es
tasca.clear()                       # deixa el diccionari buit

del és la manera directa d'esborrar; .pop(clau) és la que fas servir quan a més necessites el valor que en surt, igual que a les llistes. I com a les llistes, el diccionari és mutable: si el passes a una funció i aquesta el modifica, el canvi es veu fora. Això és el que permetrà que canviar_prioritat(tasca) funcioni sense retornar res.

  1. Recórrer un diccionari

Un for directe sobre un diccionari recorre les claus. Els tres mètodes de vista permeten triar què vols recórrer:

Mètode Produeix a cada volta
.keys() Les claus (és el mateix que el for directe)
.values() Els valors
.items() Parells (clau, valor)
tasca = {"titol": "Cartell fira", "responsable": "Marta", "dies": 3}
for clau in tasca:                      # equival a tasca.keys()
    print(clau, end=" ")                # titol responsable dies
for valor in tasca.values():
    print(valor, end=" ")               # Cartell fira Marta 3
for clau, valor in tasca.items():
    print(f"{clau:<12}: {valor}")
for clau, valor in sorted(tasca.items()):       # recorregut alfabetic per clau
    print(clau, valor)

.items() és el que faràs servir el 90 % de les vegades, perquè gairebé sempre necessites les dues coses alhora. Fixa't que el desempaquetatge for clau, valor in ... és el mateix mecanisme que ja vas veure amb enumerate i zip a 05-01. Des de Python 3.7 el diccionari conserva l'ordre d'inserció en recórrer-lo, però no t'hi recolzis per donar significat a les posicions: si necessites un ordre concret, demana'l explícitament amb sorted(), com a l'última línia.

  1. update, setdefault i què pot ser una clau

.update(altre) fusiona un altre diccionari dins del primer: afegeix les claus noves i sobreescriu les que coincideixin. És la manera neta d'aplicar diversos canvis de cop.

.setdefault(clau, valor) retorna el valor de la clau si existeix i, si no, la crea amb el valor indicat: serveix per garantir que una clau hi és sense esclafar el que ja hi hagués. I sobre les claus hi ha una regla estricta: una clau ha de ser immutable. Valen cadenes, números, booleans i tuples (05-04); no val una llista ni un altre diccionari.

tasca = {"titol": "Cartell fira", "dies": 3}
tasca.update({"dies": 4, "prioritat": "alta"})      # fusiona: dies passa a 4
tasca.setdefault("completada", False)   # no hi era: la crea en False
tasca.setdefault("dies", 99)            # ja hi era: no toca res, retorna 4

valid = {"marta": 3, 2026: "any", (1, 2): "coordenada"}
no_valid = {["marta"]: 3}       # TypeError: unhashable type: 'list'

El motiu, sense entrar en detalls: el diccionari col·loca cada valor en un lloc calculat a partir de la clau, així que si la clau pogués canviar després, el valor quedaria perdut en un lloc equivocat. Els valors, en canvi, poden ser el que vulguis: llistes, altres diccionaris, funcions. I les claus són úniques: escriure dues vegades la mateixa en un literal deixa només l'última.

  1. Diccionari per comprensió i recompte de freqüències

Igual que les llistes, els diccionaris admeten comprensió, amb la mateixa sintaxi més el parell clau: valor:

dies_per_tasca = {"Cartell fira": 3, "Menu Sole": 5, "Logotip Vidal": 2}
en_hores = {t: d * 8 for t, d in dies_per_tasca.items()}
print(en_hores)     # {'Cartell fira': 24, 'Menu Sole': 40, 'Logotip Vidal': 16}
llargues = {t: d for t, d in dies_per_tasca.items() if d > 2}
print(llargues)     # {'Cartell fira': 3, 'Menu Sole': 5}

I ara un patró clàssic que apareix en tots els programes del món: comptar freqüències. La idea és fer servir el diccionari com a marcador, amb l'element de clau i el recompte de valor.

responsables = ["Marta", "Luis", "Marta", "Nuria", "Marta", "Luis"]
recompte = {}
for nom in responsables:
    recompte[nom] = recompte.get(nom, 0) + 1
print(recompte)                         # {'Marta': 3, 'Luis': 2, 'Nuria': 1}
print(max(recompte, key=recompte.get))  # Marta -> qui te mes tasques
print(sorted(recompte.items(), key=lambda p: p[1], reverse=True))
# [('Marta', 3), ('Luis', 2), ('Nuria', 1)]

La línia decisiva és recompte[nom] = recompte.get(nom, 0) + 1, i mereix llegir-se a poc a poc. recompte.get(nom, 0) retorna el recompte actual o 0 si és la primera vegada que apareix aquest nom; se li suma 1 i es desa. Aquest 0 per defecte és el que evita el KeyError de la primera volta i estalvia un if nom in recompte:. Després, max(recompte, key=recompte.get) recorre les claus i les compara pel seu valor —el key de 04-05 aplicat a un diccionari— i sorted(...) ordena els parells pel segon element; com ordena per dins continua sent matèria d'Algorismes d'ordenació.

  1. Conjunts: elements únics i sense ordre

Un conjunt (set) és una col·lecció d'elements únics i sense ordre. No hi ha índexs: conjunt[0] dóna error. A canvi, respon la pregunta «hi és, això?» de manera immediata i elimina duplicats sense esforç.

etiquetes = {"disseny", "impremta", "client", "disseny"}
print(etiquetes)        # {'client', 'disseny', 'impremta'}  -> el duplicat desapareix
print(len(etiquetes), "impremta" in etiquetes)      # 3 True
buit_dict = {}                                  # compte: aixo es un dict
buit_set = set()                                # el conjunt buit s'escriu aixi
des_de_llista = set(["Marta", "Luis", "Marta"]) # {'Marta', 'Luis'}

L'ordre en què s'imprimeix no és el d'escriptura i no hi has de comptar. I compte amb el parany de la creació que mostren les tres últimes línies: {} no és un conjunt buit, sinó un diccionari buit. Els mètodes bàsics són quatre, i la diferència entre els dos d'esborrat és la de sempre:

Mètode Què fa Si l'element no hi és
.add(x) Afegeix x (si ja hi era, no passa res) —
.discard(x) El treu No fa res
.remove(x) El treu KeyError
.pop() Treu un element qualsevol KeyError si està buit

Existeix també frozenset, la versió immutable del conjunt: un cop creat no admet add ni remove, i la seva utilitat principal és poder fer-se servir com a clau de diccionari, cosa que un set normal no pot.

  1. Operacions entre conjunts

Aquí és on els conjunts brillen: implementen directament les operacions de la teoria de conjunts, amb operadors d'una sola lletra.

Partim de marta = {"cartell", "menu", "logotip"} i luis = {"menu", "flyer"}.

Operació Operador Mètode Resultat Significa
Unió marta | luis .union() {'cartell','menu','logotip','flyer'} En un o en un altre
Intersecció marta & luis .intersection() {'menu'} En tots dos
Diferència marta - luis .difference() {'cartell','logotip'} Al primer i no al segon
Diferència simètrica marta ^ luis .symmetric_difference() {'cartell','logotip','flyer'} En un però no en tots dos
graph LR
    A["Nomes MARTA<br/>cartell, logotip"] --- C["COMU<br/>menu"]
    C --- D["Nomes LUIS<br/>flyer"]

El diagrama es llegeix així: menu és a la zona comuna (la intersecció), cartell i logotip són exclusius de la Marta (la diferència marta - luis) i flyer ho és del Luis. La unió són els quatre; la diferència simètrica, els tres de fora del centre. Existeix a més luis <= marta, que comprova si un conjunt està contingut en un altre (aquí, False), i >= per al contrari: són útils per validar coses com «són totes les prioritats introduïdes de les admeses?».

  1. Usos típics dels conjunts

Dos usos cobreixen gairebé tots els casos reals. El primer, eliminar duplicats d'una llista en una línia: amb responsables = ["Marta", "Luis", "Marta", "Nuria", "Luis"], l'expressió sorted(set(responsables)) retorna ['Luis', 'Marta', 'Nuria']. Fixa't en el sorted(): convertir a conjunt perd l'ordre original, així que si l'ordre importa cal reordenar després (o fer servir una altra tècnica). El segon ús és comprovar pertinença en col·leccions grans: preguntar x in conjunt és moltíssim més ràpid que x in llista quan hi ha milers d'elements, perquè el conjunt no recorre res. El perquè exacte s'estudia a Algorismes de cerca i Eficiència i notació Big-O; de moment queda't amb la conseqüència pràctica: si el teu programa fa moltes comprovacions de pertinença sobre una col·lecció sense duplicats, aquesta col·lecció hauria de ser un conjunt.

  1. Llista, diccionari o conjunt: taula de decisió

Criteri Llista Diccionari Conjunt
Sintaxi [1, 2] {"a": 1} {1, 2}
S'hi accedeix per Índex Clau No s'hi accedeix: es pregunta amb in
Manté l'ordre? Sí, i significa alguna cosa Sí, d'inserció No
Admet duplicats? Sí Claus no, valors sí No
Buscar un element Recorre Directe Directe
Cas típic Moltes coses iguals Els camps d'una cosa Etiquetes, pertinença, desduplicar

Les preguntes que porten a la resposta correcta: importa l'ordre o els recorreré en seqüència? Llista. Cada dada té un nom propi? Diccionari. Només m'importa si una cosa hi és o no, i no vull repetits? Conjunt.

  1. TascaFàcil v0.9: la tasca és un diccionari

A la v0.8 vam aconseguir moltes tasques a costa de cinc llistes paral·leles fràgils. Ara arreglarem l'altra meitat del problema —la forma d'una tasca— i per veure-ho amb claredat tornem temporalment a gestionar-ne una de sola: a la v0.9 la tasca és un diccionari, i a 05-04 ajuntarem les dues idees en una llista de diccionaris.

# tascafacil.py - Estudi Alba / Versio 0.9: cada tasca es un diccionari

AMPLE = 46
PRIORITATS = ("alta", "mitjana", "baixa")
EQUIP = ("marta", "luis", "nuria")
OPCIONS = ("1", "2", "3", "4", "5")
ETIQUETES = {"disseny", "impremta", "client"}

# --- Entrada i logica sense canvis: demanar_text, demanar_opcio, demanar_enter,
#     confirmar, classificar_urgencia, mostrar_menu, pausar ---

def registrar_tasca():
    """Demana les dades d'una tasca i retorna el diccionari complet."""
    return {
        "titol": demanar_text("Titol         : "),
        "responsable": demanar_opcio("Responsable   : ", EQUIP).capitalize(),
        "prioritat": demanar_opcio("Prioritat     : ", PRIORITATS),
        "dies": demanar_enter("Dies (1-365)  : ", 1, 365),
        "etiqueta": demanar_opcio("Etiqueta      : ", sorted(ETIQUETES)),
        "completada": False,
    }

def mostrar_fitxa(tasca):
    """Pinta la fitxa completa de la tasca rebuda."""
    estat = "Completada" if tasca["completada"] else "Pendent"
    dies_estat = str(tasca["dies"]) + " / " + estat
    urgencia = classificar_urgencia(tasca["prioritat"], tasca["dies"])
    print("-" * AMPLE)
    for etiqueta, clau in (("Titol", "titol"), ("Responsable", "responsable"),
                           ("Prioritat", "prioritat"), ("Etiqueta", "etiqueta")):
        print(f"{etiqueta:<14}{tasca[clau]:>{AMPLE - 14}}")
    print(f"{'Dies / estat':<14}{dies_estat:>{AMPLE - 14}}")
    print(f"{'Urgencia':<14}{urgencia:>{AMPLE - 14}}")

def canviar_prioritat(tasca):
    """Canvia la prioritat de la tasca rebuda (la modifica al lloc)."""
    anterior = tasca["prioritat"]
    tasca["prioritat"] = demanar_opcio("Nova prioritat: ", PRIORITATS)
    print(f"Prioritat de '{tasca['titol']}': {anterior} -> {tasca['prioritat']}")

def marcar_completada(tasca):
    """Marca la tasca com a completada despres de confirmar."""
    if tasca["completada"]:
        print("La tasca ja estava completada.")
    elif confirmar(f"Marcar '{tasca['titol']}' com a completada?"):
        tasca["completada"] = True
        print("Tasca completada. Bona feina.")

def main():
    """Executa el bucle principal de l'aplicacio."""
    tasca = None                    # None significa 'encara no hi ha tasca'
    while True:
        mostrar_menu()
        opcio = demanar_opcio("Tria una opcio (1-5): ", OPCIONS)
        if opcio == "5":
            if confirmar("Segur que vols sortir?"):
                break
        elif opcio == "1":
            if tasca is None or confirmar(f"Ja existeix '{tasca['titol']}'. Substituir?"):
                tasca = registrar_tasca()
                print("Tasca registrada correctament.")
        elif tasca is None:
            print("Encara no hi ha cap tasca registrada.")
        elif opcio == "2":
            mostrar_fitxa(tasca)
        elif opcio == "3":
            canviar_prioritat(tasca)
        elif opcio == "4":
            marcar_completada(tasca)
        pausar()

if __name__ == "__main__":
    main()

El que ha canviat respecte a la v0.7, i per què importa:

  • mostrar_fitxa(tasca) té un paràmetre en comptes de cinc. Les sis variables soltes que viatjaven juntes de funció en funció eren, efectivament, una sola cosa; ara tenen nom i forma.
  • Afegir un camp ja no obliga a tocar cap signatura. Hi hem incorporat "etiqueta" sense canviar la capçalera de res. Amb la v0.7 hauria suposat un paràmetre més en quatre funcions.
  • Les funcions d'acció modifiquen el diccionari i no retornen res. canviar_prioritat(tasca) funciona perquè el diccionari és mutable i es passa per referència, com les llistes de 05-01. El nom anuncia clarament que modifica.
  • ETIQUETES és un conjunt, perquè són valors únics sense ordre l'ús dels quals és comprovar pertinença i oferir opcions; es passa sorted(ETIQUETES) a demanar_opcio perquè l'usuari les vegi sempre igual. I tasca is None substitueix la bandera hi_ha_tasca: una dada menys per mantenir sincronitzada.

Continua sense resoldre's el més important: només hi ha una tasca. Però ara que una tasca és un valor únic, desar-les totes serà tan fàcil com ficar-les en una llista.

Errors Comuns i Consells

KeyError en llegir una clau que no existeix. Comprova-ho amb in o fes servir .get(clau, defecte). I recorda que les claus distingeixen majúscules: "Titol" i "titol" són diferents; tria una convenció (minúscules) i respecta-la. Escriure malament una clau en assignar. tasca["responsble"] = "Luis" no dóna error: crea una clau nova. El símptoma apareix després, quan tasca["responsable"] retorna el valor vell. És l'error més traïdor del tipus.

Creure que {} és un conjunt buit. És un diccionari buit; el conjunt buit és set(). I no esperis ordre en un conjunt: si necessites mostrar-lo ordenat, sorted(conjunt).

Fer servir una llista com a clau. TypeError: unhashable type. Si necessites una clau composta, fes servir una tupla (05-04).

Modificar un diccionari mentre el recorres. Afegir o esborrar claus dins del for llança RuntimeError; recorre una còpia (for c in list(d.keys()):) o construeix un diccionari nou. Consell: fes servir el diccionari per a camps, no com a base de dades improvisada. Si acabes amb claus "tasca1", "tasca2", "tasca3", el que vols és una llista de diccionaris (05-04).

Exercicis

Exercici 1: Predir la sortida

Digues què imprimeix cada línia i quins errors es produeixen.

tasca = {"titol": "Cartell fira", "dies": 3}
print(tasca.get("responsable", "sense assignar"))
tasca["dies"] = tasca["dies"] + 2
tasca.setdefault("dies", 99)
tasca.setdefault("prioritat", "mitjana")
print(tasca)
print("Cartell fira" in tasca)
print(len({"a", "b", "a", "b"}))
print({"a", "b"} & {"b", "c"}, {"a", "b"} - {"b", "c"})
print(tasca["completada"])

Exercici 2: Resum de l'estudi

Donada la llista de responsables de les tasques obertes, escriu un programa que imprimeixi: quantes tasques porta cada persona (ordenades de més a menys), qui en porta més, i quins membres de l'equip EQUIP = ("Marta", "Luis", "Nuria") no tenen cap tasca assignada. Fes servir un diccionari per comptar i un conjunt per a l'última pregunta.

assignacions = ["Marta", "Luis", "Marta", "Marta", "Luis"]

Exercici 3: Fitxa amb diccionari

Escriu crear_tasca(titol, responsable, prioritat, dies) que retorni el diccionari d'una tasca amb completada en False, i resum(tasca) que retorni una cadena d'una línia amb el títol, el responsable, la prioritat en majúscules, els dies i [X] o [ ] segons l'estat. Afegeix aplicar_canvis(tasca, canvis) que rebi un diccionari de canvis i els apliqui, avisant si alguna clau no existia a la tasca.

Solucions

Solució 1.

sense assignar
{'titol': 'Cartell fira', 'dies': 5, 'prioritat': 'mitjana'}
False
2
{'b'} {'a'}
KeyError: 'completada'

.get amb defecte no falla. tasca["dies"] + 2 deixa 5, i setdefault("dies", 99) no el toca perquè la clau ja existeix; setdefault("prioritat", ...) sí que la crea. "Cartell fira" in tasca és False perquè in mira claus, no valors. El conjunt {"a","b","a","b"} té 2 elements. La intersecció és {'b'} i la diferència {'a'}. I l'última línia llança KeyError perquè mai no es va crear aquesta clau: amb tasca.get("completada", False) hauria retornat False.

Solució 2.

EQUIP = ("Marta", "Luis", "Nuria")
assignacions = ["Marta", "Luis", "Marta", "Marta", "Luis"]

recompte = {}
for nom in assignacions:
    recompte[nom] = recompte.get(nom, 0) + 1

for nom, total in sorted(recompte.items(), key=lambda p: p[1], reverse=True):
    print(f"{nom:<10}{total:>3} tasques")
print("Qui en porta mes:", max(recompte, key=recompte.get))

sense_tasques = set(EQUIP) - set(assignacions)
print("Sense tasques:", ", ".join(sorted(sense_tasques)) or "ningu")

Imprimeix «Marta 3 tasques», «Luis 2 tasques», «Qui en porta mes: Marta» i «Sense tasques: Nuria». L'última part és l'exemple perfecte de per a què serveix un conjunt: set(EQUIP) - set(assignacions) respon «qui és a l'equip i no a les assignacions» en una sola expressió, sense bucles ni banderes. Amb llistes hauria calgut recórrer l'equip comprovant cada nom.

Solució 3.

def crear_tasca(titol, responsable, prioritat, dies):
    """Retorna el diccionari d'una tasca nova, pendent per defecte."""
    return {"titol": titol, "responsable": responsable,
            "prioritat": prioritat, "dies": dies, "completada": False}

def resum(tasca):
    """Retorna una linia amb les dades principals de la tasca."""
    marca = "[X]" if tasca["completada"] else "[ ]"
    return (f"{marca} {tasca['titol']:<24}{tasca['responsable']:>8}"
            f"{tasca['prioritat'].upper():>8}{tasca['dies']:>4}d")

def aplicar_canvis(tasca, canvis):
    """Aplica els canvis a la tasca i avisa de les claus desconegudes."""
    for clau, valor in canvis.items():
        if clau not in tasca:
            print(f"Avis: '{clau}' no es un camp de la tasca; s'ignora.")
            continue
        tasca[clau] = valor

t = crear_tasca("Cartell fira", "Marta", "alta", 3)
aplicar_canvis(t, {"dies": 4, "completada": True, "color": "vermell"})
print(resum(t))     # [X] Cartell fira               Marta    ALTA   4d

El que és interessant d'aplicar_canvis és la comprovació if clau not in tasca. Sense ella, un error tipogràfic en el nom del camp afegiria una clau nova en silenci —l'error traïdor de la secció de consells— i mai no sabries per què el canvi «no ha funcionat». Fixa't també que la funció modifica el diccionari rebut i no retorna res: és legítim perquè el nom ho anuncia.

Conclusió

El diccionari guarda parells clau → valor i substitueix la posició pel nom: es crea amb {} o dict(), es llegeix amb d[clau] —que llança KeyError si falta— o amb .get(clau, defecte) —que no falla—, s'amplia i es modifica amb la mateixa assignació, i es recorre amb .keys(), .values() i sobretot .items(). .update() fusiona, .setdefault() garanteix sense esclafar, les claus han de ser immutables i úniques, i la comprensió de diccionari i el patró de recompte de freqüències amb .get(x, 0) + 1 resolen en tres línies coses que abans costaven vint. El conjunt guarda elements únics sense ordre, no s'indexa, es crea amb {...} o set() —mai amb {}, que és un diccionari—, i ofereix unió |, intersecció &, diferència - i diferència simètrica ^, a més de ser l'estructura correcta per desduplicar i per comprovar pertinença.

TascaFàcil està a la v0.9 i una tasca és per fi una sola cosa: un diccionari amb titol, responsable, prioritat, dies, etiqueta i completada. mostrar_fitxa(tasca) té un paràmetre en lloc de cinc, afegir un camp ja no obliga a tocar cap signatura, i les etiquetes de l'estudi viuen en un conjunt. Queda un últim assemblatge: la v0.8 sabia portar moltes tasques però amb llistes paral·leles fràgils, i la v0.9 sap representar una tasca perfectament però només en porta una. Ajuntar totes dues idees —una llista de diccionaris— és el que fa Tuples i estructures imbricades, on a més coneixeràs la tupla, entendràs per fi què retornava return a, b des de 04-02 i aprendràs a llegir expressions com agenda[0]["responsable"] sense parpellejar.

© Copyright 2026. Tots els drets reservats