Tancàvem el mòdul 4 amb una promesa: les dues limitacions de TascaFàcil —que només guarda una tasca i que les dades d'aquesta tasca viuen en sis variables soltes— es resolen amb estructures de dades. Aquesta lliçó ataca la primera i més urgent: com guardar molts valors sota un sol nom.
L'eina es diu llista, i és l'estructura de dades que més faràs servir en tota la teva vida com a programador: guarda una seqüència ordenada de valors, creix i minva sobre la marxa, es recorre amb un for i es pot ordenar i filtrar. Tan bon punt la tinguis, la Marta podrà portar alhora el cartell de la fira del llibre, el menú del Forn Solé i el logotip del client Vidal. I de passada tancarem els caps solts de 04-05: sorted(key=...), map i filter necessitaven una col·lecció sobre la qual treballar, i ja la tenim.
Contingut
- De les variables soltes a la llista
- Array clàssic i llista de Python
- Crear llistes, mesurar-les i indexar-les
- Talls:
[inici:fi:pas] - Mutabilitat, aliasing i còpies
- Mètodes i funcions essencials
- Recórrer:
for,enumerate,zipiin - Comprensions de llistes
sortedambkey,mapifilter- TascaFàcil v0.8: llistes paral·leles
- Errors comuns i consells
- Exercicis
- Conclusió
- De les variables soltes a la llista
Per guardar els dies estimats de tres tasques, amb el que saps fins ara només hi ha una sortida: dies_1 = 3, dies_2 = 5, dies_3 = 2. Funciona i alhora és un carreró sense sortida: no pots recórrer aquestes variables amb un bucle (cada nom és diferent i no formen cap seqüència), no pots afegir una quarta tasca sense editar el programa, no pots preguntar quantes n'hi ha ni ordenar-les. Una llista converteix aquestes tres variables en un sol objecte amb estructura:
dies = [3, 5, 2]
print(len(dies)) # 3
print(sum(dies)) # 10
dies.append(8) # una quarta tasca, en temps d'execucio
print(dies) # [3, 5, 2, 8]La regla que se'n deriva val per sempre: quan diverses variables es diuen igual llevat d'un número, el que vols és una llista.
- Array clàssic i llista de Python
A la literatura de programació apareix la paraula array (de vegades traduïda com a taula o vector), que no és exactament el mateix que una llista de Python. Un array clàssic, tal com existeix en C, Java o Pascal, és un bloc contigu de memòria amb dues restriccions fortes —mida fixa i un únic tipus de dada— a canvi de velocitat i consum mínim de memòria. La llista de Python és dinàmica i heterogènia.
| Característica | Array clàssic | Llista de Python |
|---|---|---|
| Mida | Fixa en crear-se | Creix i minva sola |
| Tipus dels elements | Tots iguals | Qualsevol barreja |
| Accés per índex | Sí, des de 0 | Sí, des de 0 |
| Inserir al mig | Manual i costós | insert() |
| Consum de memòria | Mínim | Més gran: guarda referències |
| En Python | Mòdul array, NumPy |
Tipus natiu list |
Que ["Cartell fira", 3, True, 4.5] sigui legal no vol dir que convingui. Una llista homogènia —tots els elements del mateix tipus i amb el mateix significat— és molt més fàcil de recórrer, perquè dins del for saps què tens entre mans. Si cada posició significa una cosa diferent, el que busques és una tupla (05-04) o un diccionari (05-03). I quan necessitis milions de números i la memòria importi, existeixen el mòdul array de la biblioteca estàndard i la biblioteca externa NumPy, molt usada en càlcul numèric: no els desenvolupem aquí, però convé saber que hi són.
- Crear llistes, mesurar-les i indexar-les
Hi ha tres maneres habituals de crear una llista, i len() per mesurar-la:
equip = ["Marta", "Luis", "Nuria"] # literal
lletres = list("Alba") # amb list(): ['A', 'l', 'b', 'a']
pendents = [] # buida, per omplir-la despres
print(len(equip), len(pendents)) # 3 0La llista buida és el punt de partida del patró acumulador de 03-02, només que ara acumules elements en comptes de sumar números. len() és la mateixa funció que feies servir amb cadenes: totes dues són seqüències. Cada element té una posició, i aquesta posició comença a zero:
titols = ["Cartell fira del llibre", "Menu Forn Sole", "Logotip client Vidal"]
print(titols[0]) # Cartell fira del llibre
print(titols[2]) # Logotip client Vidal
print(titols[3]) # IndexError: list index out of rangeUna llista de tres elements té índexs 0, 1 i 2: l'últim índex vàlid és sempre len(llista) - 1. Els índexs negatius compten des del final i estalvien calcular longituds: en aquesta llista, -1 és el mateix element que 2, -2 el mateix que 1 i -3 el mateix que 0. Per això titols[-1] és la manera idiomàtica de dir «l'últim», molt millor que titols[len(titols) - 1]. No existeix -0, perquè -0 és 0.
- Talls:
[inici:fi:pas]
[inici:fi:pas]Un tall (slice) extreu un tros i retorna una llista nova. Els tres números són opcionals. La regla clau, i la font eterna de confusió: inici s'inclou, fi NO. L'avantatge del conveni és que fi - inici dóna directament quants elements en surten. Els exemples parteixen de dies = [3, 5, 2, 8, 1, 6].
| Expressió | Resultat | Explicació |
|---|---|---|
dies[1:4] |
[5, 2, 8] |
De l'1 al 3; el 4 queda fora |
dies[:3] |
[3, 5, 2] |
Des del principi |
dies[3:] |
[8, 1, 6] |
Fins al final |
dies[-2:] |
[1, 6] |
Els dos últims |
dies[::2] |
[3, 2, 1] |
De dos en dos, des del principi |
dies[::-1] |
[6, 1, 8, 2, 5, 3] |
Al revés |
dies[:] |
[3, 5, 2, 8, 1, 6] |
Còpia completa |
dies[4:2] |
[] |
Rang impossible: buida, sense error |
Dos detalls importants. Un tall mai no dóna IndexError encara que et passis de llarg: dies[2:99] retorna el que hi hagi. I dies[:] sembla redundant, però és la manera clàssica d'obtenir una còpia superficial.
- Mutabilitat, aliasing i còpies
Les llistes són mutables: pots canviar-ne el contingut sense crear una llista nova, cosa que amb les cadenes no podies (02-01). prioritats[1] = "alta" substitueix el segon element i ja està. Fins aquí, còmode. Ara el que sorprèn tothom:
originals = ["Cartell fira", "Menu Sole"]
copia = originals # de debo es una copia?
copia.append("Logotip Vidal")
print(originals) # ['Cartell fira', 'Menu Sole', 'Logotip Vidal']
print(copia is originals) # TrueHem modificat copia i ha canviat originals. El motiu és el que vas estudiar a 04-03 amb les referències: copia = originals no copia la llista, copia la referència; els dos noms apunten al mateix objecte, i això s'anomena aliasing. Per copiar de debò hi ha tres formes equivalents, que veuràs sota el diagrama.
graph LR
A[originals] --> L["Llista A en memoria<br/>Cartell fira, Menu Sole"]
B[copia] --> L
C[de_debo] --> M["Llista B en memoria<br/>Cartell fira, Menu Sole"]
copia_1 = originals.copy() # la mes explicita i recomanable
copia_2 = list(originals) # constructor a partir de l'original
copia_3 = originals[:] # tall complet, el classic
print(len(originals), copia_1 is originals) # 2 FalseAixò té una conseqüència directa sobre les funcions, i és nova respecte a 04-03. Allà vam veure que passar un argument immutable no permet a la funció tocar la variable de qui la crida. Amb una llista és al revés:
def afegir_tasca(llista, titol):
"""Afegeix un titol a la llista rebuda (la modifica)."""
llista.append(titol)
def buidar_malament(llista):
llista = [] # reassigna el nom LOCAL: no es veu fora
def buidar_be(llista):
llista.clear() # modifica l'objecte: si que es veu fora
agenda = ["Cartell fira"]
afegir_tasca(agenda, "Menu Sole")
print(agenda) # ['Cartell fira', 'Menu Sole']La funció rep una referència a la mateixa llista, així que els seus canvis es veuen fora. És potentíssim —així afegirà tasques la v0.8— i també perillós: una funció que modifica en silenci una llista aliena provoca sorpreses. Regla pràctica: o modifica i ho diu en el seu nom (afegir_tasca, ordenar_agenda), o treballa sobre una còpia i retorna el resultat. I fixa't en el contrast entre buidar_malament i buidar_be: reassignar el paràmetre només canvia el nom local, mentre que cridar un mètode canvia l'objecte que tots dos comparteixen.
- Mètodes i funcions essencials
Els mètodes es criden sobre la llista amb un punt i gairebé tots la modifiquen al lloc; les funcions integrades es criden amb la llista dins dels parèntesis i retornen un valor sense tocar-la.
| Mètode | Què fa | Retorna |
|---|---|---|
.append(x) |
Afegeix x al final |
None |
.insert(i, x) |
Insereix x a la posició i |
None |
.extend(altra) |
Afegeix tots els elements d'altra |
None |
.remove(x) |
Esborra la primera aparició de x (ValueError si no hi és) |
None |
.pop(i) |
Treu l'element i (l'últim si s'omet) |
L'element |
.clear() |
Buida la llista | None |
.index(x) |
Posició de la primera aparició (ValueError si no hi és) |
Enter |
.count(x) |
Quantes vegades apareix x |
Enter |
.sort() |
Ordena al lloc | None |
.reverse() |
Inverteix l'ordre al lloc | None |
tasques = ["Cartell fira", "Menu Sole"]
tasques.insert(0, "Revisar correu") # es cola en primera posicio
tasques.extend(["Targetes Vidal", "Flyer"]) # afegeix dues de cop
print(tasques.index("Menu Sole"), tasques.count("Flyer")) # 2 1
ultima = tasques.pop() # treu 'Flyer' i el retorna
tasques.remove("Menu Sole") # esborra per valor, no per posicio
malament = tasques.sort() # sort() retorna None
print(malament) # None -> has perdut la llistaDiferència decisiva: pop esborra per posició i retorna l'element; remove esborra per valor i no retorna res. I el parany número u de les llistes és aquesta última línia: els mètodes que modifiquen retornen None, així que mai no guardis el seu resultat. Les funcions integrades, en canvi, retornen alguna cosa nova i no toquen la llista:
dies = [3, 5, 2, 8, 1]
print(len(dies), sum(dies), min(dies), max(dies)) # 5 19 1 8
print(f"Mitjana: {sum(dies) / len(dies):.2f}") # Mitjana: 3.80
print(sorted(dies), dies) # [1, 2, 3, 5, 8] [3, 5, 2, 8, 1] -> intactaLa regla per triar: .sort() si vols que la llista quedi ordenada; sorted() si necessites conservar l'ordre original. Tots dos admeten reverse=True. Com ordenen per dins i quant costa és matèria d'Algorismes d'ordenació i d'Eficiència i notació Big-O; aquí els fem servir com a eines del llenguatge.
- Recórrer:
for, enumerate, zip i in
for, enumerate, zip i inEl for de 03-02 està fet per a això. Recórrer la llista directament —for titol in titols:— és la forma preferent en Python: a cada volta, titol pren el valor d'un element, sense índexs, sense len() i sense possibilitat d'IndexError. Quan sí que necessites la posició —numerar un llistat, per exemple— fes servir enumerate(), que produeix dos valors per volta:
for numero, titol in enumerate(titols, start=1):
print(f"{numero}. {titol}") # 1. Cartell fira del llibre, 2. Menu...start=1 fa que la numeració que veu l'usuari comenci a 1 encara que els índexs interns continuïn començant a 0: just el que necessita un menú. Quan tens dues llistes en paral·lel, zip() les aparella:
responsables = ["Marta", "Luis", "Nuria"]
for titol, responsable in zip(titols, responsables):
print(f"{titol:<24}{responsable:>10}")
print("Marta" in responsables) # True
print("Alba" not in responsables) # Truezip s'atura amb la llista més curta sense avisar: si una en té un element de més, aquest element desapareix del recorregut. Les dues últimes línies fan servir l'operador in de 02-02 per comprovar pertinença. Com busca in per dins, i per què en una llista llarga triga més que en un conjunt, es veu a Algorismes de cerca i a Diccionaris i conjunts.
- Comprensions de llistes
Aquest patró apareix constantment: crear una llista buida (dobles = []), recórrer una altra seqüència i afegir alguna cosa a cada volta (dobles.append(d * 2)). Python ofereix una forma condensada d'escriure exactament això, la comprensió de llista, que es llegeix de dins cap enfora: per a cada d de dies, calcula d * 2 i posa'l a la llista.
dobles = [d * 2 for d in dies] # transformar: [6, 10, 4, 16, 2]
llargues = [d for d in dies if d > 3] # filtrar: [5, 8]
altes = [t.upper() for t in titols if "fira" in t] # filtrar i transformar| Forma | Significat |
|---|---|
[f(x) for x in llista] |
Transformar tots els elements |
[x for x in llista if cond] |
Quedar-se amb alguns |
[f(x) for x in llista if cond] |
Filtrar i transformar |
I ara la part que gairebé mai no s'explica: quan NO fer-les servir. No la facis servir si l'expressió no cap còmodament en una línia, si necessites condicions imbricades, si a dins cal imprimir o demanar dades a l'usuari, o si encadenes dos o tres for. Una cosa com [t.upper() if len(t) > 10 else t.lower() for t in titols if "e" in t] és legal i és il·legible: demana a crits un bucle normal. L'objectiu no era escriure menys, sinó llegir millor.
sorted amb key, map i filter
sorted amb key, map i filterA 04-05 va quedar pendent l'ordre superior sobre col·leccions. Ja el podem tancar. sorted(llista, key=funcio) ordena segons el que retorni funcio aplicada a cada element, no segons l'element en si:
titols = ["Menu Sole", "Cartell fira del llibre", "Flyer", "Logotip Vidal"]
print(sorted(titols, key=len))
# ['Flyer', 'Menu Sole', 'Logotip Vidal', 'Cartell fira del llibre']
PRIORITATS = ("alta", "mitjana", "baixa")
prioritats = ["baixa", "alta", "mitjana", "alta"]
print(sorted(prioritats, key=lambda p: PRIORITATS.index(p)))
# ['alta', 'alta', 'mitjana', 'baixa']Amb una lambda pots inventar-te qualsevol criteri. Ordenar les prioritats alfabèticament donaria alta, baixa, mitjana, que no és el seu ordre lògic; en canvi PRIORITATS.index(p) retorna 0 per a "alta", 1 per a "mitjana" i 2 per a "baixa", i ordenar per aquest número dóna l'ordre correcte. És exactament el de 04-05: sorted no sap res de prioritats, només d'ordenar; el criteri s'injecta des de fora. I key=str.lower ordena ignorant majúscules, mentre que reverse=True inverteix el resultat.
map(funcio, llista) aplica una funció a tots els elements i filter(funcio, llista) es queda amb aquells per als quals retorna True. Totes dues retornen un objecte mandrós que cal convertir amb list():
| Objectiu | Amb comprensió | Amb map/filter |
|---|---|---|
| Transformar | [d * 2 for d in dies] |
list(map(lambda d: d * 2, dies)) |
| Filtrar | [d for d in dies if d > 3] |
list(filter(lambda d: d > 3, dies)) |
En Python modern es prefereix la comprensió: més curta, sense list() i més llegible. map i filter continuen sent útils quan la funció ja existeix i té nom (map(str.upper, titols) és netíssim), i els has de reconèixer perquè abunden en el codi aliè.
- TascaFàcil v0.8: llistes paral·leles
La v0.7 guardava una tasca en sis variables soltes. La v0.8 guarda moltes tasques en cinc llistes paral·leles: l'element d'índex i de cada llista es refereix a la mateixa tasca.
graph LR
T["titols"] --> I0["L'index 0 de les quatre llistes<br/>descriu la mateixa tasca"]
R["responsables"] --> I0
P["prioritats"] --> I0
C["completades"] --> I0
Les funcions d'entrada (demanar_text, demanar_opcio, demanar_enter, confirmar), la de lògica (classificar_urgencia) i mostrar_menu/pausar es conserven intactes. Canvien les d'acció i el main():
# tascafacil.py - Estudi Alba / Versio 0.8: moltes tasques en llistes paralleles
def mostrar_llistat(titols, responsables, prioritats, completades):
"""Pinta totes les tasques numerades des de l'1."""
if len(titols) == 0:
print("No hi ha cap tasca registrada.")
return
for numero, titol in enumerate(titols, start=1):
i = numero - 1
marca = "[X]" if completades[i] else "[ ]"
print(f"{numero:>2}. {marca} {titol:<22}{responsables[i]:>8}{prioritats[i]:>7}")
print("-" * AMPLE)
print(f"Total: {len(titols)} tasques, {completades.count(True)} completades.")
def registrar_tasca(titols, responsables, prioritats, dies, completades):
"""Demana una tasca nova i l'afegeix al final de les cinc llistes."""
titols.append(demanar_text("Titol : "))
responsables.append(demanar_opcio("Responsable : ", EQUIP).capitalize())
prioritats.append(demanar_opcio("Prioritat : ", PRIORITATS))
dies.append(demanar_enter("Dies (1-365) : ", 1, 365))
completades.append(False)
print(f"Tasca {len(titols)} registrada correctament.")
def triar_index(titols):
"""Demana el numero d'una tasca i retorna el seu index, o -1 si no n'hi ha cap."""
if len(titols) == 0:
print("No hi ha cap tasca registrada.")
return -1
return demanar_enter(f"Numero de tasca (1-{len(titols)}): ", 1, len(titols)) - 1
def main():
"""Executa el bucle principal de l'aplicacio."""
titols, responsables, prioritats, dies, completades = [], [], [], [], []
while True:
mostrar_menu()
opcio = demanar_opcio("Tria una opcio (1-5): ", OPCIONS)
if opcio == "5":
if confirmar("Segur que vols sortir?"):
print("Fins despres. TascaFacil es tanca.")
break
elif opcio == "1":
registrar_tasca(titols, responsables, prioritats, dies, completades)
elif opcio == "2":
mostrar_llistat(titols, responsables, prioritats, completades)
elif opcio == "3":
i = triar_index(titols)
if i >= 0:
prioritats[i] = demanar_opcio("Nova prioritat: ", PRIORITATS)
print(f"Prioritat de '{titols[i]}' actualitzada.")
elif opcio == "4":
i = triar_index(titols)
if i >= 0 and completades[i]:
print("Aquesta tasca ja estava completada.")
elif i >= 0:
completades[i] = True
print(f"'{titols[i]}' completada. Bona feina.")
pausar()
if __name__ == "__main__":
main()El que ha canviat i per què:
registrar_tascaja no retorna res: modifica les llistes que rep. Ho pot fer perquè les llistes són mutables (secció 5); el nom i el docstring ho anuncien.triar_indextradueix el número que veu l'usuari a l'índex intern restant 1. Aquest- 1és la frontera entre «primera tasca» per a la Marta i «índex 0» per a Python, i convé tenir-la en un únic lloc.enumerate(..., start=1)numera el llistat sense comptadors manuals icompletades.count(True)compta les fetes sense bucle. A més desapareix la banderahi_ha_tasca:len(titols) == 0respon al mateix i encara diu quantes n'hi ha.
I ara el problema nou que hem creat. Les cinc llistes han d'estar sincronitzades sempre: si algú afegeix un camp i oblida un append, es desalineen i el responsable d'una tasca apareix al costat del títol d'una altra. No hi ha error ni avís: el programa continua funcionant i mentint. Esborrar una tasca exigeix cinc pop coordinats, i afegir un camp obliga a tocar la signatura de totes les funcions. Les cinc llistes paral·leles són, en realitat, una sola llista de tasques que encara no sabem escriure.
Errors Comuns i Consells
Confondre índex i posició humana. El tercer element és llista[2]. Aquest desfasament d'un (off-by-one) és l'error més freqüent de l'ofici: en pintar per a l'usuari, enumerate(..., start=1); en accedir, resta 1 en un únic lloc. Esperar que .sort() retorni alguna cosa. ordenada = llista.sort() deixa ordenada valent None; si necessites una llista nova, sorted(llista). El mateix amb append, reverse, insert i clear. I .remove(x) i .index(x) amb un valor que no hi és llancen ValueError: comprova-ho abans amb if x in llista:.
Creure que copia = llista copia. Copia la referència. Fes servir .copy(), list() o [:], i comprova amb is si tens dubtes. I no esborris elements mentre recorres la llista: si dins d'un for fas llista.remove(x), el recorregut se salta elements perquè les posicions es desplacen sota els teus peus. La solució segura és construir una llista nova amb els que vols conservar, normalment amb una comprensió.
Consell: fes servir el for directe sempre que puguis. for t in titols: és més clar i més segur que for i in range(len(titols)):. I mantén les llistes homogènies: una llista conté «moltes coses del mateix tipus», no «una cosa repartida en trossos».
Exercicis
Exercici 1: Predir la sortida
Digues què imprimeix cada print i explica per què.
dies = [3, 5, 2, 8, 1, 6]
print(dies[2], dies[-1], dies[1:3])
copia = dies
copia.append(4)
print(len(dies))
altra = dies[:]
altra.clear()
print(len(dies), len(altra))
print(dies.sort(), dies[0])Exercici 2: Estadístiques de l'estudi
Amb les llistes de sota, imprimeix: el nombre de tasques, el total i la mitjana de dies, el títol de la tasca més llarga, els títols de prioritat "alta" i els títols ordenats per dies de major a menor. Fes servir comprensions i sorted(key=...) on encaixin.
titols = ["Cartell fira", "Menu Sole", "Logotip Vidal", "Flyer estiu"]
responsables = ["Marta", "Luis", "Nuria", "Marta"]
prioritats = ["alta", "mitjana", "alta", "baixa"]
dies = [3, 5, 2, 8]Exercici 3: Eliminar una tasca
Escriu eliminar_tasca(titols, responsables, prioritats, dies, titol), que esborri de les quatre llistes la tasca amb aquest títol sense desalinear-les i avisi si no existeix. Explica després, en dues frases, per què aquesta funció resulta incòmoda d'escriure i de mantenir.
Solucions
Solució 1.
dies[2] és el tercer element, dies[-1] l'últim i dies[1:3] inclou els índexs 1 i 2 però no el 3. copia = dies és aliasing: l'append afecta l'única llista que hi ha i len(dies) passa de 6 a 7. altra = dies[:] sí que és una còpia, així que buidar-la no toca l'original: 7 i 0. I .sort() ordena al lloc retornant None; després d'ordenar, el primer element és el menor, 1.
Solució 2.
print(f"Tasques: {len(titols)}")
print(f"Total: {sum(dies)} dies, mitjana {sum(dies) / len(dies):.2f}")
print(f"La mes llarga: {titols[dies.index(max(dies))]} ({max(dies)} dies)")
altes = [titols[i] for i in range(len(titols)) if prioritats[i] == "alta"]
print(f"Prioritat alta: {', '.join(altes)}")
per_dies = sorted(titols, key=lambda t: dies[titols.index(t)], reverse=True)
print(per_dies) # ['Flyer estiu', 'Menu Sole', 'Cartell fira', 'Logotip Vidal']Surten 4 tasques, 18 dies en total, mitjana 4.50, la més llarga «Flyer estiu» i dues de prioritat alta. dies.index(max(dies)) dóna la posició del màxim, i aquesta posició serveix per llegir el títol corresponent: així funcionen les llistes paral·leles. Fixa't en la retorçada que queda l'última línia: per ordenar per dies cal buscar cada títol a la seva pròpia llista per esbrinar-ne l'índex. Amb una llista de diccionaris (05-04) serà sorted(agenda, key=lambda t: t["dies"]) i s'ha acabat.
Solució 3.
def eliminar_tasca(titols, responsables, prioritats, dies, titol):
"""Elimina de les quatre llistes la tasca amb el titol indicat."""
if titol not in titols:
print(f"No existeix cap tasca anomenada '{titol}'.")
return False
i = titols.index(titol)
titols.pop(i)
responsables.pop(i)
prioritats.pop(i)
dies.pop(i)
return TrueÉs incòmoda per dos motius. Primer, rep quatre llistes només per esborrar una tasca: si demà afegeixes un camp, cal canviar la signatura i totes les crides. Segon, la seva correcció depèn que els quatre pop s'executin sempre junts i amb el mateix índex; n'hi ha prou d'oblidar-ne un perquè totes les tasques posteriors quedin barrejades sense cap error que ho delati.
Conclusió
Una llista guarda molts valors sota un sol nom i resol el que les variables soltes no podien: comptar, recórrer, sumar, ordenar i créixer en temps d'execució. S'hi accedeix per índex des de 0, amb índexs negatius per comptar des del final i IndexError si et passes; es trosseja amb talls [inici:fi:pas], on el final mai no s'inclou. És mutable, i d'aquí l'aliasing: copia = llista no copia res, i per copiar de debò hi ha .copy(), list() i [:]. Els seus mètodes modifiquen al lloc i retornen None, mentre que len, sum, min, max i sorted retornen un valor nou. Es recorre amb for, amb enumerate quan cal la posició i amb zip quan hi ha diverses llistes; in comprova pertinença. Les comprensions condensen el patró «crear, recórrer, afegir» sempre que la línia continuï sent llegible. I amb sorted(key=...), map i filter hem tancat el capítol de l'ordre superior de 04-05.
TascaFàcil ha arribat a la v0.8 i per fi gestiona la feina real de l'estudi: registra tantes tasques com calgui, les llista numerades i permet canviar la prioritat o completar l'enèsima. Però ho ha aconseguit amb cinc llistes paral·leles que cal sincronitzar a mà, i ja has vist com de fràgil és: un pop oblidat i el llistat comença a mentir en silenci. El problema no és la llista, és que l'estem fent servir per a una cosa que no li toca: una llista guarda moltes coses iguals, i el que necessitem és agrupar els camps diferents d'una mateixa tasca sota un nom. Això arriba a Diccionaris i conjunts i es remata a Tuples i estructures imbricades. Abans, a Cadenes de caràcters, mirarem de prop l'altra seqüència que fas servir des del mòdul 2 sense veure-la com a tal —el text— i n'exprimirem els mètodes: els títols, els responsables i els codis de tasca d'Estudi Alba són tots cadenes, i hi ha molt a treure'n.
Fonaments de la Programació
Mòdul 1: Introducció a la Programació
- Què és la programació?
- Història de la programació
- Llenguatges de programació
- Entorns de desenvolupament
- Del problema a l'algorisme
Mòdul 2: Conceptes Bàsics
- Variables i tipus de dades
- Operadors i expressions
- Entrada i sortida de dades
- Conversió de tipus i validació de dades
Mòdul 3: Estructures de Control
Mòdul 4: Funcions i Procediments
- Definició i ús de funcions
- Paràmetres i retorn de valors
- Àmbit de variables
- Descompondre un programa en funcions
- Funcions com a valors: lambda i ordre superior
Mòdul 5: Estructures de Dades
- Llistes i arrays
- Cadenes de caràcters
- Diccionaris i conjunts
- Tuples i estructures imbricades
- Desar dades en fitxers: text, CSV i JSON
Mòdul 6: Algorismes Bàsics
Mòdul 7: Objectes i Organització del Codi
- De les dades als objectes: classes i instàncies
- Atributs, mètodes i constructor
- Col·leccions d'objectes
- Mòduls, paquets i importacions
Mòdul 8: Bones Pràctiques i Eines
- Documentació i comentaris
- Depuració i gestió d'errors
- Control de versions
- Proves automatitzades
- Estil, llegibilitat i refactorització
