TascaFàcil v0.10 fa gairebé tot el que la Marta necessita: registra les tasques de l'estudi, les llista ordenades per prioritat, permet canviar-les, completar-les i veure el repartiment de feina. I tanmateix, cada vegada que la Marta tanca el programa tot s'esborra. L'endemà torna a trobar-se l'agenda buida. És l'últim cap solt del mòdul i, per a un programa que aspira a ser útil, el més greu: sense persistència no hi ha eina, hi ha demostració.

Aquesta lliçó resol exactament això. Aprendràs a escriure dades en un fitxer i a recuperar-les, en els tres formats que cobreixen la pràctica totalitat dels casos: text pla per al més simple, CSV per al que acabarà en un full de càlcul i JSON per desar estructures completes com la nostra llista de diccionaris. En acabar, l'agenda d'Estudi Alba continuarà allà demà al matí.

Contingut

  1. Memòria i disc: per què es perd tot
  2. Rutes, directori de treball i pathlib
  3. Obrir fitxers: modes, with i codificació
  4. Text pla: escriure i llegir
  5. CSV: dades en files i columnes
  6. JSON: estructures completes
  7. Text, CSV o JSON: quin fer servir
  8. Comprovar si el fitxer existeix
  9. TascaFàcil v0.11: l'agenda sobreviu
  10. Errors comuns i consells
  11. Exercicis
  12. Conclusió del mòdul

  1. Memòria i disc: per què es perd tot

Tot el que has creat fins ara —variables, llistes, diccionaris— viu a la memòria RAM, que és ràpida i volàtil: quan el procés acaba, el sistema operatiu recupera aquest espai i el contingut desapareix. El disc és lent en comparació, però persistent: el que s'hi escriu continua existint després d'apagar l'ordinador.

graph LR
    A["Programa en execucio<br/>agenda a la memoria RAM"] -->|desar: escriure| B["Fitxer al disc<br/>tasques.json"]
    B -->|carregar: llegir| A
    A -->|tancar el programa| C["La memoria s'allibera<br/>les dades es perden"]

Persistència és el nom d'aquest pont, i té dues direccions amb nom propi: serialitzar (o desar) és traduir una estructura de Python a text o bytes que puguin escriure's, i deserialitzar (o carregar) és llegir aquest text i reconstruir l'estructura original. Un fitxer és, en el fons, una seqüència de bytes amb un nom; el que anomenem «format» —text, CSV, JSON— no és més que un acord sobre com s'organitzen aquests bytes per poder tornar a interpretar-los.

  1. Rutes, directori de treball i pathlib

Per obrir un fitxer cal dir on és. Una ruta relativa (tasques.json, dades/tasques.json) s'interpreta a partir del directori de treball, que és la carpeta des de la qual s'ha llançat el programa. Una ruta absoluta (/home/marta/alba/tasques.json en Linux o macOS, C:\Users\marta\alba\tasques.json en Windows) comença a l'arrel i no depèn de res.

La relativa és portable —funciona en qualsevol ordinador sempre que el fitxer sigui al costat del programa— i l'absoluta no, així que llevat de casos molt concrets es prefereix la relativa. El mòdul pathlib de la biblioteca estàndard ofereix Path, un objecte que representa una ruta i funciona igual en tots els sistemes operatius:

from pathlib import Path

ruta = Path("tasques.json")
print(ruta.name, ruta.suffix)       # tasques.json .json
print(ruta.exists())                # False si encara no existeix
print(Path.cwd())                   # el directori de treball actual
desti = Path("dades") / "tasques.json"      # l'operador / uneix rutes

Aquesta / que uneix un Path amb un text és la manera moderna i segura de construir rutes: evita haver d'escriure barres a mà i funciona en Windows sense canviar res. Com que aquí el fitxer viurà al costat del programa, farem servir rutes relatives simples.

  1. Obrir fitxers: modes, with i codificació

La funció open(ruta, mode, encoding=...) obre un fitxer i retorna un objecte sobre el qual llegir o escriure. El mode decideix què s'hi pot fer i què passa amb el que hi hagués a dins:

Mode Significa Si el fitxer existeix Si no existeix
"r" Llegir (per defecte) El llegeix FileNotFoundError
"w" Escriure El buida del tot El crea
"a" Afegir al final Escriu al darrere El crea
"x" Crear en exclusiva FileExistsError El crea

Retén l'avís sobre "w": obrir un fitxer en mode escriptura esborra tot el seu contingut a l'acte, fins i tot abans que hi escriguis res. És la causa número u de pèrdues de dades dels programes de principiant. Si el que vols és afegir, el mode és "a".

Un fitxer obert cal tancar-lo perquè el sistema aboqui el que s'ha escrit i alliberi el recurs. En comptes de fer-ho a mà, es fa servir sempre el bloc with:

with open("tasques.txt", "w", encoding="utf-8") as fitxer:
    fitxer.write("Cartell fira del llibre\n")
# aqui el fitxer ja esta tancat, passi el que passi dins del bloc

with garanteix el tancament fins i tot si es produeix un error dins del bloc, i és la raó per la qual mai no veuràs en codi modern un open() solt seguit de close(). Tot el que es fa amb el fitxer va a dins, indentat. L'altre paràmetre imprescindible és encoding="utf-8". Com vas veure a 05-02, el text es desa al disc com a bytes, i la codificació és la taula de traducció. Si no l'indiques, Python fa servir la codificació per defecte del sistema, que en alguns Windows no és UTF-8: el fitxer es llegirà malament en un altre ordinador i els accents apareixeran com Solé. Escriu-la sempre, tant en llegir com en escriure.

  1. Text pla: escriure i llegir

El format més simple: línies de text, sense més estructura que la que tu li donis.

titols = ["Cartell fira del llibre", "Menu Forn Sole", "Logotip Vidal"]

with open("titols.txt", "w", encoding="utf-8") as f:
    for titol in titols:
        f.write(titol + "\n")           # write NO afegeix el salt de linia
    f.writelines([t + "\n" for t in titols])    # writelines tampoc no l'afegeix

with open("titols.txt", "a", encoding="utf-8") as f:
    f.write("Flyer estiu\n")            # mode 'a': s'afegeix al final, sense esborrar

La diferència entre write i print és exactament aquesta: print afegeix un salt de línia al final i write no. Si oblides el "\n", tot el fitxer acaba en una única línia gegant. Per llegir hi ha tres maneres:

with open("titols.txt", "r", encoding="utf-8") as f:
    contingut = f.read()            # tot el fitxer en una sola cadena
with open("titols.txt", "r", encoding="utf-8") as f:
    linies = f.readlines()          # llista de cadenes, cadascuna amb el seu \n
with open("titols.txt", "r", encoding="utf-8") as f:
    for linia in f:                 # la forma preferent: linia a linia
        print(linia.rstrip())       # rstrip treu el \n del final

Recórrer el fitxer directament amb for linia in f: és el recomanable: no carrega el fitxer sencer a memòria, així que funciona igual amb tres línies que amb tres milions. I gairebé sempre cal aplicar .rstrip(), perquè cada línia llegida conserva el seu salt de línia final; sense ell, comparar linia == "Marta" fallaria sempre per culpa d'aquest "\n" invisible.

Combinant això amb split de 05-02 ja es pot desar una tasca sencera per línia:

with open("tasques.txt", "w", encoding="utf-8") as f:
    for t in agenda:
        f.write(f"{t['titol']};{t['responsable']};{t['prioritat']};{t['dies']}\n")
with open("tasques.txt", "r", encoding="utf-8") as f:
    for linia in f:
        titol, responsable, prioritat, dies = linia.rstrip().split(";")

Funciona, i ja se li veuen les costures: si un títol conté un punt i coma, el split produeix cinc camps i el desempaquetatge peta. Aquest problema exacte és el que resol el format següent.

  1. CSV: dades en files i columnes

CSV (comma-separated values) és un format de text per a taules: una línia per fila i un separador entre camps. La seva gran virtut és que Excel, LibreOffice i Google Sheets l'obren directament, així que és la manera habitual de lliurar dades a algú que no programa.

titol;responsable;prioritat;dies;completada
Cartell fira del llibre;Marta;alta;3;False
Menu Forn Sole;Luis;mitjana;5;True

La primera línia és la capçalera, amb els noms de les columnes. El separador estàndard és la coma, però aquí és habitual el punt i coma, perquè els nostres fulls de càlcul fan servir la coma com a separador decimal. El mòdul csv de la biblioteca estàndard s'ocupa de tots els detalls:

import csv

agenda = [
    {"titol": "Cartell fira", "responsable": "Marta", "prioritat": "alta", "dies": 3},
    {"titol": "Menu, amb tapes", "responsable": "Luis", "prioritat": "mitjana", "dies": 5}]

with open("tasques.csv", "w", encoding="utf-8", newline="") as f:
    escriptor = csv.DictWriter(f, fieldnames=["titol", "responsable", "prioritat", "dies"])
    escriptor.writeheader()             # escriu la fila de capcalera
    escriptor.writerows(agenda)         # una fila per diccionari

with open("tasques.csv", "r", encoding="utf-8", newline="") as f:
    for fila in csv.DictReader(f):      # cada fila es un diccionari
        print(fila["titol"], fila["dies"], type(fila["dies"]))

Quatre coses que convé entendre d'aquest codi:

  • DictWriter i DictReader treballen amb diccionaris, que és just el que té la nostra agenda. Els seus cosins csv.writer i csv.reader fan el mateix amb llistes, i són més simples quan no hi ha capçalera.
  • fieldnames fixa l'ordre de les columnes i ha de coincidir amb les claus dels diccionaris. I newline="" a l'open és un detall tècnic obligatori amb el mòdul csv: sense ell, en Windows apareixen línies en blanc entre fila i fila.
  • Tot el que es llegeix d'un CSV és text. fila["dies"] val "3", no 3; si necessites el número, int(fila["dies"]). És la mateixa norma que amb input() a 02-03.

I el problema de les comes dins d'un camp queda resolt: el títol "Menu, amb tapes" s'escriu entre cometes automàticament i es torna a llegir sencer. Això és precisament el que fa el mòdul csv i el que no fa un split(",") escrit a mà.

  1. JSON: estructures completes

JSON (JavaScript Object Notation) és un format de text pensat per representar estructures imbricades: llistes dins de diccionaris dins de llistes, amb els seus tipus conservats. És el format en què es comuniquen pràcticament totes les aplicacions d'internet, i encaixa com un guant amb el que vas aprendre a 05-04.

Python JSON
dict objecte { }
list, tuple array [ ]
str string (sempre amb cometes dobles)
int, float number
True / False true / false
None null

Compte amb dos detalls: una tupla es desa com a array i torna convertida en llista, i els conjunts (set) no tenen equivalent, així que cal convertir-los a llista abans de desar. El mòdul json ofereix quatre funcions que es distingeixen per una s de string:

Funció Què fa
json.dump(dada, fitxer) Escriu l'estructura en un fitxer
json.load(fitxer) Llegeix un fitxer i retorna l'estructura
json.dumps(dada) Retorna l'estructura com a cadena
json.loads(cadena) Converteix una cadena en estructura
import json

agenda = [{"titol": "Cartell fira", "responsable": "Marta", "dies": 3,
           "completada": False}]
with open("tasques.json", "w", encoding="utf-8") as f:
    json.dump(agenda, f, indent=2, ensure_ascii=False)
with open("tasques.json", "r", encoding="utf-8") as f:
    recuperada = json.load(f)

print(recuperada == agenda)         # True -> l'estructura torna intacta
print(type(recuperada[0]["dies"]))  # <class 'int'> -> els tipus es conserven

Els dos paràmetres opcionals són importants a la pràctica. indent=2 escriu el fitxer amb salts de línia i indentació, de manera que una persona pugui llegir-lo i corregir-lo amb un editor; sense ell surt tot en una línia. I ensure_ascii=False fa que els accents i la ç s'escriguin tal qual: per defecte, json.dump els converteix en seqüències com \u00e7, que són vàlides però il·legibles.

El gran avantatge sobre el CSV es veu a l'última línia: JSON conserva els tipus. Els enters tornen com a enters i els booleans com a booleans, sense conversions manuals. Per això serà el format principal de TascaFàcil.

  1. Text, CSV o JSON: quin fer servir

Text pla CSV JSON
Estructura Cap Taula de files i columnes Imbricada, a qualsevol nivell
Conserva els tipus? No No: tot és text
L'obre un full de càlcul? No No
Mòdul necessari Cap csv json
Ideal per a Registres, notes, logs Lliurar dades a algú Desar l'estat del programa

En resum: text quan només hi ha línies soltes i no les tornaràs a interpretar; CSV quan les dades són una taula i algú les obrirà amb un full de càlcul; JSON quan vols desar i recuperar una estructura de Python tal qual. Res no impedeix combinar-los, que és just el que farem: JSON com a magatzem de treball i CSV com a exportació per a la Marta.

  1. Comprovar si el fitxer existeix

La primera vegada que s'executa el programa no hi ha res desat, i obrir en mode "r" un fitxer inexistent llança FileNotFoundError. La comprovació prèvia és senzilla:

ruta = Path("tasques.json")
if ruta.exists():
    with open(ruta, "r", encoding="utf-8") as f:
        agenda = json.load(f)
else:
    agenda = []         # primera execucio: comencem amb l'agenda buida

Aquest patró —comprovar i decidir— és suficient per al nostre programa, encara que té dos límits: no cobreix que el fitxer existeixi però estigui corrupte (un JSON a mig escriure) ni que existeixi sense permís de lectura. La solució robusta és intentar l'operació i capturar l'error si passa, amb try/except, que s'estudia a Depuració i gestió d'errors. De moment, Path.exists() ens val.

  1. TascaFàcil v0.11: l'agenda sobreviu

Amb tres funcions noves, el programa deixa d'oblidar. carregar_tasques es crida en arrencar, desar_tasques en sortir, i exportar_csv quan la Marta vol el llistat en un full de càlcul. El menú passa a set opcions.

# tascafacil.py - Estudi Alba / Versio 0.11: l'agenda es desa al disc
import csv, json
from pathlib import Path

RUTA_JSON = Path("tasques.json")
RUTA_CSV = Path("tasques.csv")
CAMPS = ("titol", "responsable", "prioritat", "dies", "completada")
OPCIONS = ("1", "2", "3", "4", "5", "6", "7")
# --- Resta de constants i funcions: sense canvis respecte a la v0.10 ---

def desar_tasques(agenda, ruta=RUTA_JSON):
    """Desa l'agenda completa en un fitxer JSON."""
    with open(ruta, "w", encoding="utf-8") as fitxer:
        json.dump(agenda, fitxer, indent=2, ensure_ascii=False)
    print(f"Agenda desada a {ruta} ({len(agenda)} tasques).")

def carregar_tasques(ruta=RUTA_JSON):
    """Retorna l'agenda desada, o una llista buida si no hi ha fitxer."""
    if not ruta.exists():
        print("No hi ha agenda previa: comencem de zero.")
        return []
    with open(ruta, "r", encoding="utf-8") as fitxer:
        agenda = json.load(fitxer)
    print(f"Agenda carregada des de {ruta}: {len(agenda)} tasques.")
    return agenda

def exportar_csv(agenda, ruta=RUTA_CSV):
    """Exporta l'agenda a un CSV que la Marta pugui obrir al full de calcul."""
    if not agenda:
        print("No hi ha res per exportar.")
        return
    with open(ruta, "w", encoding="utf-8", newline="") as fitxer:
        escriptor = csv.DictWriter(fitxer, fieldnames=CAMPS, delimiter=";")
        escriptor.writeheader()
        escriptor.writerows(agenda)
    print(f"Exportades {len(agenda)} tasques a {ruta}.")

def main():
    """Executa el bucle principal de l'aplicacio."""
    agenda = carregar_tasques()
    while True:
        mostrar_menu()
        opcio = demanar_opcio("Tria una opcio (1-7): ", OPCIONS)
        if opcio == "7":
            if confirmar("Segur que vols sortir?"):
                desar_tasques(agenda)
                print("Fins despres. TascaFacil es tanca.")
                break
        elif opcio == "1":
            registrar_tasca(agenda)
        elif opcio == "2":
            mostrar_llistat(agenda)
        elif opcio == "3":
            tasca = triar_tasca(agenda)
            if tasca is not None:
                canviar_prioritat(tasca)
        elif opcio == "4":
            tasca = triar_tasca(agenda)
            if tasca is not None:
                marcar_completada(tasca)
        elif opcio == "5":
            resum_per_responsable(agenda)
        elif opcio == "6":
            exportar_csv(agenda)
        pausar()

if __name__ == "__main__":
    main()

Els detalls que fan que això funcioni:

  • carregar_tasques retorna [] quan no hi ha fitxer, així que la primera execució no falla i la resta del programa no necessita saber res del disc: rep una llista de diccionaris, com sempre.
  • desar_tasques es crida just abans del break, dins de la confirmació de sortida. És el moment exacte en què l'agenda està completa.
  • Les rutes són paràmetres amb valor per defecte (04-02): el programa fa servir tasques.json sense dir res, però qualsevol pot cridar desar_tasques(agenda, Path("copia.json")) per fer una còpia de seguretat.
  • CAMPS és una tupla —constant, no ha de canviar (05-04)— i fixa l'ordre de les columnes del CSV, que s'escriu amb delimiter=";" perquè el full de càlcul configurat en català reparteixi bé les columnes.

Queden dues limitacions honestes. Si el programa es tanca de manera anormal —un tall de llum, un Ctrl+C— els canvis es perden, perquè només es desa en sortir; la solució és cridar desar_tasques després de cada modificació, una línia per opció de menú. I si el JSON està corrupte, json.load llançarà un error que encara no sabem capturar. Totes dues coses s'arreglen al mòdul 8.

Errors Comuns i Consells

Obrir en mode "w" el que volies llegir. El fitxer es buida en aquell instant i no hi ha marxa enrere. Abans d'escriure cap open(..., "w"), comprova que aquesta és de debò la teva intenció.

Oblidar el "\n" en escriure, amb la qual cosa el fitxer acaba sent una sola línia interminable, o oblidar el .rstrip() en llegir, amb la qual cosa les comparacions fallen per un caràcter invisible enganxat al final.

No indicar encoding="utf-8". Funciona al teu ordinador i es trenca al del costat, amb accents convertits en símbols estranys. Posa-ho sempre.

Esperar que el CSV retorni números. Tot el que surt d'un CSV és text: converteix amb int() o float(). I desar un conjunt en JSON llança TypeError: Object of type set is not JSON serializable; converteix-lo abans amb list(el_meu_conjunt).

Consell: desa en un fitxer temporal i reanomena. Per a dades importants, escriu primer a tasques.tmp i reanomena en acabar; així, si el programa s'interromp a mitges, el fitxer bo continua intacte.

Consell: separa la lògica de la persistència. desar_tasques i carregar_tasques són les úniques funcions que toquen el disc; la resta del programa treballa amb llistes i diccionaris sense assabentar-se'n. És el mateix principi de 04-04 —separar entrada i sortida de la lògica— aplicat als fitxers.

Exercicis

Exercici 1: Predir el comportament

Explica què fa cada bloc i què contindrà notes.txt al final. Indica també quin error es produiria si notes.txt no existís en arribar al tercer bloc.

with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("Cartell fira\n")
    f.write("Menu Sole\n")
with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("Logotip Vidal\n")
with open("notes.txt", "a", encoding="utf-8") as f:
    f.write("Flyer estiu")
with open("notes.txt", "r", encoding="utf-8") as f:
    for i, linia in enumerate(f, start=1):
        print(i, repr(linia))

Exercici 2: De CSV a JSON

Escriu csv_a_json(ruta_csv, ruta_json), que llegeixi un CSV amb capçalera titol;responsable;dies;completada separat per punt i coma, converteixi dies a enter i completada al booleà corresponent (el text "True" és True, qualsevol altre és False), i desi el resultat com a JSON llegible. Si el CSV no existeix, ha d'avisar i no fer res.

Exercici 3: Còpia de seguretat amb data

Escriu fer_copia(agenda, etiqueta) que desi l'agenda en un fitxer anomenat copia-<etiqueta>.json dins d'una carpeta copies, creant-la si no existeix (Path.mkdir(exist_ok=True)), i retorni la ruta usada. Després, escriu llistar_copies() que imprimeixi els noms de tots els fitxers .json d'aquesta carpeta fent servir Path.glob("*.json").

Solucions

Solució 1.

1 'Logotip Vidal\n'
2 'Flyer estiu'

El primer bloc crea el fitxer amb dues línies. El segon l'obre una altra vegada en mode "w", cosa que esborra tot abans d'escriure: les dues primeres línies desapareixen. El tercer, en mode "a", afegeix al final sense esborrar, però sense "\n", així que l'última línia queda sense salt final. En llegir amb repr() es veuen els \n explícits, que és la manera de comprovar què hi ha realment a cada línia. Si el fitxer no existís en arribar al tercer bloc, no passaria res: el mode "a" el crea. L'error FileNotFoundError només apareixeria al quart bloc, que obre en mode "r".

Solució 2.

def csv_a_json(ruta_csv, ruta_json):
    """Converteix un CSV de tasques en un JSON amb els tipus correctes."""
    ruta_csv = Path(ruta_csv)
    if not ruta_csv.exists():
        print(f"No existeix el fitxer {ruta_csv}.")
        return []
    agenda = []
    with open(ruta_csv, "r", encoding="utf-8", newline="") as f:
        for fila in csv.DictReader(f, delimiter=";"):
            agenda.append({
                "titol": fila["titol"].strip(),
                "responsable": fila["responsable"].strip().capitalize(),
                "dies": int(fila["dies"]),
                "completada": fila["completada"].strip() == "True"})
    with open(ruta_json, "w", encoding="utf-8") as f:
        json.dump(agenda, f, indent=2, ensure_ascii=False)
    print(f"Convertides {len(agenda)} tasques.")
    return agenda

La conversió de tipus és el moll de l'exercici, i és on es veu la diferència entre els dos formats: del CSV surt "3" i "True" com a text, i cal traduir-los a 3 i True a mà. L'expressió fila["completada"].strip() == "True" és el booleà: una comparació ja retorna True o False, així que no cal cap if. Fixa't a més que la guarda amb return [] va al principi, seguint el patró de 04-02.

Solució 3.

def fer_copia(agenda, etiqueta):
    """Desa l'agenda a copies/copia-<etiqueta>.json i retorna la ruta."""
    carpeta = Path("copies")
    carpeta.mkdir(exist_ok=True)            # no falla si ja existeix
    desti = carpeta / f"copia-{etiqueta}.json"
    with open(desti, "w", encoding="utf-8") as f:
        json.dump(agenda, f, indent=2, ensure_ascii=False)
    return desti

def llistar_copies():
    """Imprimeix les copies disponibles, de la mes recent a la mes antiga."""
    carpeta = Path("copies")
    if not carpeta.exists():
        print("Encara no hi ha cap copia.")
        return
    for ruta in sorted(carpeta.glob("*.json"), reverse=True):
        print(f"{ruta.name:<28}{ruta.stat().st_size:>8} bytes")

fer_copia(agenda, "2026-08-04")
llistar_copies()    # copia-2026-08-04.json         412 bytes

carpeta / f"copia-{etiqueta}.json" combina l'operador de rutes de pathlib amb una f-string, que és la manera neta de construir noms de fitxer variables. mkdir(exist_ok=True) evita haver de comprovar abans si la carpeta existeix. I glob("*.json") retorna totes les rutes que encaixen amb el patró; en ordenar-les al revés i anomenar les còpies amb la data en format aaaa-mm-dd, surten automàticament de la més recent a la més antiga.

Conclusió del mòdul

La persistència és el pont entre la memòria, que s'esborra, i el disc, que no. Es travessa amb open() dins d'un bloc with —que garanteix el tancament— indicant el mode (r per llegir, w per escriure sabent que buida el fitxer, a per afegir, x per crear en exclusiva) i sempre encoding="utf-8". Sobre aquesta base, tres formats: text pla, que s'escriu amb write (recordant el "\n") i es llegeix línia a línia amb for linia in f (recordant el .rstrip()); CSV, la taula que obre qualsevol full de càlcul, gestionada amb csv.DictWriter i csv.DictReader, que resolen la capçalera, el separador i les comes dins d'un camp, però retornen tot com a text; i JSON, que desa estructures imbricades completes amb json.dump/json.loadindent perquè es llegeixi, ensure_ascii=False per als accents— i és l'únic que conserva els tipus. I abans de llegir, Path.exists(), a l'espera del try/except de 08-02.

Amb això es tanca el mòdul 5 i queden assentades les cinc estructures que necessitaràs a diari: la llista per a moltes coses del mateix tipus, amb els seus índexs, talls, mètodes i comprensions; la cadena com a seqüència immutable amb el seu catàleg de mètodes i el pont split/join; el diccionari per donar nom a cada camp; el conjunt per a valors únics i pertinença; i la tupla per a registres fixos i valors retornats. Combinant-les neix l'estructura que sosté gairebé qualsevol programa real: la llista de diccionaris.

TascaFàcil ha recorregut en cinc lliçons el camí que va d'un programa de joguina a una eina: d'una tasca en sis variables soltes (v0.7) a llistes paral·leles fràgils (v0.8), d'aquí a la tasca com a diccionari (v0.9), a l'agenda com a llista de diccionaris amb tot el menú operatiu (v0.10) i, per fi, a una v0.11 que recorda. La Marta pot tancar el programa, anar-se'n a casa i trobar-se la seva agenda intacta l'endemà, a més d'exportar-la a CSV quan necessita ensenyar el repartiment de feina.

I aquest èxit porta el problema següent, que és el millor tipus de problema. Quan l'agenda tingui dues-centes tasques desades, «buscar la del client Vidal» deixarà de ser trivial i «ordenar per prioritat» deixarà de ser gratis. Al mòdul 6 obrirem les eines que hem estat fent servir com a caixes negres: Algorismes de cerca explicarà com es localitza una dada i per què buscar en un conjunt és tan ràpid, Algorismes d'ordenació mostrarà què fa sorted per dins, i Eficiència i notació Big-O et donarà per fi el vocabulari per dir quant costa cada cosa.

© Copyright 2026. Tots els drets reservats