Ja saps decidir amb if i repetir amb for i while, però els teus bucles encara són rígids: recorren la seqüència completa tant sí com no. En aquesta lliçó aprendràs a prendre el control fi de l'execució: break per sortir d'un bucle tan bon punt trobes el que busques, continue per saltar-te elements, pass com a marcador de posició, la poc coneguda clàusula else dels bucles, el patró while True per a menús que es repeteixen fins que l'usuari decideix sortir, i la moderna sentència match/case de Python 3.10. Amb totes elles construirem el primer menú interactiu de Papyrus, l'esquelet sobre el qual creixerà l'aplicació de l'Anna durant la resta del curs.
Contingut
break: sortir del bucle abans d'horacontinue: saltar a la iteració següentpass: la instrucció que no fa res- La clàusula
elseen bucles - Bucles infinits controlats:
while True+break match/case: selecció per patrons (Python 3.10+)- Projecte: el menú interactiu de Papyrus
break: sortir del bucle abans d'hora
La sentència break ("trencar") acaba el bucle immediatament: Python salta a la primera instrucció després del bucle, sense completar la volta actual ni fer les restants.
El cas d'ús per excel·lència és la cerca: en Lluís pregunta si Papyrus té Hamlet. Tan bon punt el trobem, no té sentit continuar mirant la resta del catàleg.
cataleg = ["L'Odissea", "Hamlet", "El Quixot"]
cercat = "Hamlet"
for titol in cataleg:
print(f"Comprovant '{titol}'...")
if titol == cercat:
print(f"Trobat! '{cercat}' es al cataleg.")
break
print("Cerca acabada.")Sortida:
Fixa-t'hi: El Quixot no es comprova mai. Amb un catàleg de 3 llibres tant és, però amb 30 000 la diferència és enorme.
Detalls importants de break:
- Només es pot usar dins d'un bucle (
forowhile); a fora produeixSyntaxError. - En bucles imbricats,
breaksurt només del bucle més intern que el conté, no de tots. - Gairebé sempre apareix dins d'un
if: "si passa això, deixa d'iterar".
continue: saltar a la iteració següent
Mentre break abandona el bucle, continue ("continuar") abandona només la volta actual: salta directament a la iteració següent, sense executar la resta del bloc.
L'Anna vol imprimir la llista de llibres vendibles, saltant-se els esgotats:
cataleg = ["L'Odissea", "Hamlet", "El Quixot", "Faust"]
estocs = [4, 6, 8, 0]
print("Llibres disponibles per a la venda:")
for i, titol in enumerate(cataleg):
if estocs[i] == 0:
continue # esgotat: passem al seguent sense imprimir res
print(f"- {titol} ({estocs[i]} u.)")Sortida:
Faust (acabat d'arribar al catàleg, però amb estoc 0) se salta netament. El patró if condicio_de_descart: continue al començament del bloc s'anomena de vegades "clàusula de guarda" i té un gran avantatge de llegibilitat: el cas "normal" del bucle queda sense indentació extra, en lloc d'embolicar-ho tot amb un if gegant.
Comparativa ràpida de les dues sentències:
| Sentència | Què interromp | El bucle... | Ús típic |
|---|---|---|---|
break |
El bucle sencer | Acaba ja | "Trobat, deixo de cercar" |
continue |
Només la volta actual | Segueix amb la següent | "Aquest element no m'interessa, següent" |
flowchart TD
A[Següent element] --> B{descartar?}
B -- "continue" --> A
B -- No --> C[Processar element]
C --> D{objectiu complert?}
D -- "break" --> E[Sortir del bucle]
D -- No --> A
pass: la instrucció que no fa res
pass és exactament això: una sentència buida. Existeix perquè la sintaxi de Python exigeix que tot bloc indentat contingui almenys una instrucció; quan encara no saps què posar-hi (o deliberadament no vols fer res), pass omple el buit sense efectes.
opcio = "3"
if opcio == "1":
print("Mostrant cataleg...")
elif opcio == "2":
pass # TODO: cerca de llibres, la implementarem mes avall
else:
print("Opcio no reconeguda.")Sense el pass, aquest elif amb el cos buit donaria IndentationError. Els seus usos habituals:
- Esquelets: escriure primer l'estructura del programa (branques, bucles, i en el futur funcions i classes) i omplir els blocs a poc a poc.
- Ignorar casos a propòsit, deixant constància explícita que no és un oblit.
No confonguis pass amb continue: dins d'un bucle, pass no salta res (l'execució segueix a la línia següent); simplement "no fa res" i el flux continua amb normalitat.
La clàusula else en bucles
Aquí arriba una peculiaritat molt de Python: els bucles for i while poden portar un bloc else. El seu significat sorprèn al principi: l'else s'executa si el bucle ha acabat de manera natural, sense break.
Per a què serveix? Per al patró de cerca que hem vist abans: què passa si el llibre no hi és? Sense else necessitaríem una variable "bandera" (flag):
# Versio amb bandera (funciona, pero fa mes soroll)
cataleg = ["L'Odissea", "Hamlet", "El Quixot"]
cercat = "Faust"
trobat = False
for titol in cataleg:
if titol == cercat:
trobat = True
break
if trobat:
print(f"'{cercat}' es al cataleg.")
else:
print(f"'{cercat}' no hi es. Anna pot demanar-lo al distribuidor.")Amb l'else del bucle, la bandera desapareix:
# Versio amb for/else (idiomatica en Python)
cataleg = ["L'Odissea", "Hamlet", "El Quixot"]
cercat = "Faust"
for titol in cataleg:
if titol == cercat:
print(f"'{cercat}' es al cataleg.")
break
else:
print(f"'{cercat}' no hi es. Anna pot demanar-lo al distribuidor.")Sortida:
Com llegir-lo sense confondre's: pensa en l'else del bucle com un "si no hi ha hagut break" (alguns l'anomenen la clàusula nobreak). El flux exacte:
- El bucle recorre tots els elements sense que s'executi cap
break→ en acabar, s'executa l'else. - S'executa un
breaken qualsevol volta → l'elsese salta.
Dues advertències:
- L'
elseva alineat amb elfor/while, no amb capifinterior. Un descuit d'indentació canvia el significat del tot. - És una construcció poc coneguda fins i tot entre programadors amb experiència; usa-la per a cerques (el seu cas estrella) i acompanya-la d'un comentari si creus que qui llegeixi el codi pot no conèixer-la.
També funciona amb while: l'else s'executa quan la condició es torna falsa (sortida natural), però no si en surts amb break.
Bucles infinits controlats: while True + break
A la lliçó anterior el bucle infinit era un error a evitar. Però hi ha una versió deliberada i controlada que és un patró fonamental: while True amb un break interior. S'usa quan el programa ha de repetir alguna cosa indefinidament fins que l'usuari decideixi parar — exactament el que fa qualsevol menú, caixer automàtic o aplicació interactiva.
while True:
resposta = input("Escriu 'sortir' per acabar: ")
if resposta == "sortir":
print("Fins aviat!")
break
print(f"Has escrit: {resposta}")Com que True sempre és cert, el bucle no acaba mai per la seva condició: l'única sortida és el break. Això no és un bucle infinit accidental, perquè la sortida existeix i és clara; la clau és garantir que el break és assolible.
Aquest patró també resol del tot la validació d'entrades que vam deixar a mitges a fitxa_llibre.py:
while True:
text = input("Estoc inicial del llibre: ")
if text.isdigit(): # la cadena conte nomes digits?
estoc = int(text)
break
print("Entrada no valida. Escriu un nombre enter, per exemple: 4")
print(f"Estoc registrat: {estoc}")isdigit() és un mètode de les cadenes que retorna True si tots els seus caràcters són dígits (el veurem juntament amb la resta de mètodes de str al mòdul 4; de moment, usa'l tal qual). El bucle insisteix fins a rebre un nombre vàlid, i només llavors converteix i surt. Comparada amb el while resposta != ... de la lliçó anterior, aquesta forma evita duplicar l'input() o inicialitzar variables artificials: per això és la preferida en Python.
match/case: selecció per patrons (Python 3.10+)
Quan un programa ha de reaccionar de manera diferent segons el valor concret d'una variable (l'opció d'un menú, un codi d'estat, un tipus de client), una cadena d'if/elif funciona, però des de Python 3.10 hi ha una alternativa més expressiva: la sentència match.
opcio = "2"
match opcio:
case "1":
print("Mostrant el cataleg complet...")
case "2":
print("Cercador de llibres...")
case "3":
print("Sortint de Papyrus. Fins dema, Anna!")
case _:
print("Opcio no valida.")Com funciona:
match expressio:avalua l'expressió una vegada.- Cada
case patro:es compara en ordre; el primer que encaixa executa el seu bloc i la sentència acaba (no hi ha "caiguda" al cas següent, a diferència delswitchd'altres llenguatges: aquí no necessites capbreak). case _:és el comodí: encaixa amb qualsevol cosa, i actua com l'elsefinal. Ha d'anar en darrer lloc.- Si cap cas no encaixa i no hi ha comodí, simplement no s'executa res (sense error).
A més dels valors literals, els patrons bàsics permeten dues coses molt útils:
Alternatives amb | (o barra vertical): un mateix cas per a diversos valors.
resposta = input("Confirmar la venda? (s/n): ")
match resposta:
case "s" | "S" | "si" | "Si":
print("Venda confirmada.")
case "n" | "N" | "no":
print("Venda descartada.")
case _:
print("Resposta no reconeguda.")Condició extra amb if (anomenada guarda): el cas només encaixa si a més es compleix la condició.
estoc = 2
match estoc:
case 0:
print("Esgotat.")
case n if n <= 3:
print(f"Estoc baix: en queden {n}.")
case n:
print(f"Estoc correcte: {n} unitats.")En case n if n <= 3:, el patró n és un patró de captura: encaixa amb qualsevol valor i el guarda a la variable n, però la guarda if n <= 3 filtra quan s'accepta. És una porta d'entrada als patrons estructurals més avançats de match (desempaquetar llistes, diccionaris o objectes), que agafaran sentit quan coneguis aquestes estructures als mòduls 4 i 5.
match o if/elif? Guia ràpida:
| Situació | Recomanació |
|---|---|
| Comparar una mateixa variable contra valors concrets (menús, codis) | match guanya en claredat |
Condicions heterogènies (estoc > 0 and es_soci, rangs, diverses dades) |
if/elif |
| El teu codi ha de funcionar en Python < 3.10 | if/elif obligatòriament |
Projecte: el menú interactiu de Papyrus
Ajuntem totes les peces de la lliçó en un script nou per al projecte: menu.py, dins de la carpeta papyrus (amb el .venv activat, com sempre). És el primer programa de Papyrus que conversa amb l'Anna: es repeteix fins que ella decideix sortir.
NOM_BOTIGA = "Papyrus"
cataleg = ["L'Odissea", "Hamlet", "El Quixot"]
preus = [12.50, 9.95, 15.90]
estocs = [4, 6, 8]
print(f"Benvinguda a la gestio de {NOM_BOTIGA}")
while True:
print()
print("1. Veure cataleg")
print("2. Cercar un llibre")
print("3. Sortir")
opcio = input("Tria una opcio (1-3): ")
match opcio:
case "1":
print(f"\n{'Titol':<12} {'Preu':>8} {'Estoc':>6}")
print("-" * 28)
for i, titol in enumerate(cataleg):
print(f"{titol:<12} {preus[i]:>6.2f} € {estocs[i]:>6}")
case "2":
cercat = input("Titol a cercar: ")
if not cercat:
print("No has escrit res.")
continue
for i, titol in enumerate(cataleg):
if titol.lower() == cercat.lower():
print(f"'{titol}': {preus[i]:.2f} €, estoc {estocs[i]}.")
break
else:
print(f"'{cercat}' no es al cataleg.")
case "3":
print(f"Tancant {NOM_BOTIGA}. Fins dema, Anna!")
break
case _:
print("Opcio no valida. Tria 1, 2 o 3.")Repassa com hi col·labora cada eina:
while Truemanté el menú viu: després de cada operació, es torna a mostrar.match opciodespatxa cada opció amb un cas net, icase _captura els errors de tecleig.- A la cerca,
continuefa de guarda si l'Anna prem Intro sense escriure (truthiness de la cadena buida, com a la lliçó 02-01): torna al menú sense executar la cerca. for/break/else: elbreaktalla tan bon punt hi ha coincidència i l'elsedel bucle cobreix el cas "no trobat" sense variables bandera. (lower()passa el text a minúscules perquè la cerca no distingeixi majúscules; més sobre mètodes de cadenes al mòdul 4.)breakalcase "3"és l'única sortida delwhile True: fixa't que trenca el bucle exterior perquèmatchno és cap bucle —breakicontinuetravessen la sentènciamatchi actuen sobre el bucle que la conté.
Una sessió d'exemple:
Benvinguda a la gestio de Papyrus 1. Veure cataleg 2. Cercar un llibre 3. Sortir Tria una opcio (1-3): 2 Titol a cercar: hamlet 'Hamlet': 9.95 €, estoc 6. 1. Veure cataleg 2. Cercar un llibre 3. Sortir Tria una opcio (1-3): 3 Tancant Papyrus. Fins dema, Anna!
Aquest menú és deliberadament senzill: al mòdul 3 el reorganitzarem amb funcions (una per opció) i al mòdul 6 farà que el catàleg sobrevisqui entre sessions guardant-lo en fitxers. L'esquelet, però, ja no canviarà: while True + match + break és el patró estàndard de les aplicacions de consola.
Errors Comuns i Consells
- Esperar que
breaksurti de tots els bucles imbricats: només surt del més intern. Si necessites sortir de diversos nivells, sol ser senyal que aquest codi mereix ser una funció (mòdul 3), onreturnsurt de tot de cop. - Malinterpretar l'
elsedel bucle com a "si el bucle no s'ha executat cap vegada": fals. Amb una seqüència buida, el bucle acaba sensebreak... i l'elsesí que s'executa. Recorda:else= "no hi ha hagutbreak". - Usar
breakocontinuefora d'un bucle (per exemple, dins d'unifsolt o esperant que tallin unmatch):SyntaxError. Només tenen sentit dins defor/while. - Abusar de
continue: diverses guardes seguides a l'inici del bucle són llegibles;continues repartits per mig bloc fan el flux difícil de seguir. Si et passa, replanteja les condicions. - Oblidar el
breakde sortida en unwhile True: llavors sí que tens un bucle infinit de debò. En escriurewhile True:, escriu elcase/ifde sortida amb el seubreakabans d'omplir la resta. - Escriure
case "1" | "2":quan cada valor necessita lògica diferent: l'alternativa|és per a casos que comparteixen bloc. Si els blocs difereixen, són casos separats. - Usar
matchamb Python antic: en versions anteriors a la 3.10 donaSyntaxError. Comprova la teva versió ambpython --version; si mantens codi per a versions velles, usaif/elif. - Consell:
passés útil mentre construeixes, però no hauria d'arribar a la versió final de l'script llevat que ignorar el cas sigui una decisió conscient — i llavors, comenta-ho.
Exercicis
Exercici 1: primera venda esgotada
Donades vendes_pendents = [2, 1, 3, 2, 4] (unitats demanades per diversos clients, en ordre) i un estoc = 6 de Hamlet, recorre les comandes amb un for: serveix cada comanda restant de l'estoc i imprimeix Comanda de N u. servida (en queden M). Si una comanda no es pot servir completa, imprimeix Estoc insuficient per a la comanda de N u. i deixa de processar comandes en aquell moment. Si totes s'han servit, imprimeix al final Totes les comandes servides (pista: for/else).
Exercici 2: informe saltant els descatalogats
Donades les llistes titols = ["L'Odissea", "Hamlet", "El Quixot", "Faust"] i estats = ["actiu", "actiu", "descatalogat", "actiu"], imprimeix un informe numerat (començant per 1) només dels llibres actius, usant continue per saltar els descatalogats. La numeració ha de ser consecutiva per als mostrats (1, 2, 3), no la posició original.
Exercici 3: caixer de Papyrus amb match
Escriu un while True que demani a l'Anna un codi d'operació i reaccioni amb match:
"v"o"venda"→ demana un import i suma'l a un acumuladorcaixa(parteix decaixa = 0.0)."d"o"devolucio"→ demana un import i resta'l decaixa."t"→ imprimeix el total actual amb dos decimals."x"→ imprimeix el total final i surt.- Qualsevol altra cosa → missatge d'error.
Solucions
Solució 1:
vendes_pendents = [2, 1, 3, 2, 4]
estoc = 6
for comanda in vendes_pendents:
if comanda > estoc:
print(f"Estoc insuficient per a la comanda de {comanda} u.")
break
estoc -= comanda
print(f"Comanda de {comanda} u. servida (en queden {estoc})")
else:
print("Totes les comandes servides")Amb estoc 6, se serveixen les comandes de 2 i 1 (en queden 3), la de 3 (en queden 0) i la de 2 ja no es pot servir: break. Com que hi ha hagut break, l'else no s'executa — exactament el que volem. Prova de canviar estoc = 12 i veuràs el missatge final.
Solució 2:
titols = ["L'Odissea", "Hamlet", "El Quixot", "Faust"]
estats = ["actiu", "actiu", "descatalogat", "actiu"]
numero = 0
for i, titol in enumerate(titols):
if estats[i] == "descatalogat":
continue
numero += 1
print(f"{numero}. {titol}")La clau és portar un comptador propi (numero) que només s'incrementa després de la guarda amb continue: així els descatalogats no consumeixen número i la llista mostrada queda 1. L'Odissea, 2. Hamlet, 3. Faust.
Solució 3:
caixa = 0.0
while True:
codi = input("Operacio (v/d/t/x): ")
match codi:
case "v" | "venda":
caixa += float(input("Import de la venda: "))
case "d" | "devolucio":
caixa -= float(input("Import retornat: "))
case "t":
print(f"Total en caixa: {caixa:.2f} €")
case "x":
print(f"Tancament. Total final: {caixa:.2f} €")
break
case _:
print("Codi no reconegut. Usa v, d, t o x.")El patró complet de la lliçó en miniatura: while True com a cor del programa, | per acceptar sinònims, case _ per als errors de tecleig i un únic break com a sortida. Com sempre, float() fallarà si l'Anna escriu text a l'import — la xarxa de seguretat arribarà al mòdul 7.
Conclusió
Els teus bucles han deixat de ser trens sense frens: amb break pares tan bon punt trobes el que busques, amb continue et saltes el que no interessa, amb pass reserves el lloc del que està per escriure, amb l'else dels bucles detectes cerques sense èxit sense variables bandera, i amb while True + break has construït el patró universal dels programes interactius. A més, match/case et dona una forma moderna i llegible de despatxar opcions. Tot plegat ha quedat encaixat a menu.py, el primer programa de Papyrus que dialoga amb l'Anna i l'esquelet de tot el que ve.
Queda un últim superpoder d'aquest mòdul. Hauràs notat que molts dels nostres bucles segueixen el mateix patró: recórrer una llista per construir-ne una altra (preus amb IVA, títols filtrats per estoc...). Python té una sintaxi específica, compacta i elegantíssima per a aquest patró: les comprensions de llistes. Són el tret d'identitat del codi pythònic, i amb elles tancarem el mòdul a la propera lliçó.
Curs de Programació en Python
Mòdul 1: Introducció a Python
- Introducció a Python
- Configuració de l'Entorn de Desenvolupament
- Sintaxi de Python i Tipus de Dades Bàsics
- Variables i Constants
- Entrada i Sortida Bàsica
- Entorns Virtuals i Gestió de Paquets
Mòdul 2: Estructures de Control
Mòdul 3: Funcions i Mòduls
- Definició de Funcions
- Arguments de Funció
- Funcions Lambda
- Mòduls i Paquets
- Visió General de la Biblioteca Estàndard
Mòdul 4: Estructures de Dades
Mòdul 5: Programació Orientada a Objectes
Mòdul 6: Gestió de Fitxers
- Lectura i Escriptura de Fitxers
- Treball amb Fitxers CSV
- Gestió de Dades JSON
- Operacions amb Fitxers i Directoris
Mòdul 7: Gestió d'Errors i Excepcions
- Introducció a les Excepcions
- Gestió d'Excepcions
- Llançament d'Excepcions
- Excepcions Personalitzades
- Bones Pràctiques i Registre d'Errors amb logging
Mòdul 8: Temes Avançats
- Anotacions de Tipus (type hints)
- Decoradors
- Generadors
- Gestors de Context
- Concurrència: Fils i Processos
- Asyncio per a la Programació Asíncrona
Mòdul 9: Proves i Depuració
- Introducció a les Proves
- Proves Unitàries amb unittest
- Proves amb pytest
- Desenvolupament Guiat per Proves
- Tècniques de Depuració
- Ús de pdb per a la Depuració
Mòdul 10: Desenvolupament Web amb Python
- Introducció al Desenvolupament Web
- Fonaments del Framework Flask
- Construcció d'APIs REST amb Flask
- Introducció a Django
- Construcció d'Aplicacions Web amb Django
Mòdul 11: Ciència de Dades amb Python
- Introducció a la Ciència de Dades
- NumPy per a la Computació Numèrica
- Pandas per a la Manipulació de Dades
- Matplotlib per a la Visualització de Dades
- Introducció a l'Aprenentatge Automàtic amb scikit-learn
