Introduzione
I cicli for e while sono tra gli strumenti più importanti in Python quando bisogna ripetere operazioni su grandi quantità di dati. Un caso molto pratico, spesso sottovalutato, è l’elaborazione di file di testo: log applicativi, esportazioni CSV, report, file di configurazione o semplici liste di righe.
In questi scenari non basta “leggere il file”: serve spesso scorrere le righe, filtrare contenuti, contare occorrenze, cercare pattern e fermarsi appena si trova l’informazione utile. Qui i cicli diventano fondamentali, perché permettono di lavorare in modo ordinato, leggibile e soprattutto efficiente.
In questo tutorial vedremo come usare for e while per analizzare un file di testo riga per riga, gestire una ricerca semplice e produrre un piccolo report finale. L’obiettivo è mostrare un uso realistico e professionale dei cicli, con attenzione alla chiarezza del codice.
Codice completo
from pathlib import Path
def crea_file_di_esempio(percorso: Path) -> None:
"""Crea un file di testo di esempio con righe miste."""
contenuto = [
"INFO 2026-01-10 Avvio del servizio",
"WARNING 2026-01-10 Memoria quasi esaurita",
"INFO 2026-01-10 Connessione stabilita",
"ERROR 2026-01-10 Timeout durante la richiesta",
"INFO 2026-01-10 Operazione completata",
"ERROR 2026-01-10 Impossibile salvare il file",
"INFO 2026-01-10 Chiusura del servizio",
]
percorso.write_text("n".join(contenuto), encoding="utf-8")
def analizza_log(percorso: Path, parola_chiave: str) -> dict:
"""
Analizza un file di testo riga per riga.
Conta le righe totali, gli errori e le righe che contengono una parola chiave.
"""
totale_righe = 0
numero_errori = 0
righe_trovate = []
# Ciclo for: ideale per scorrere un file riga per riga
with percorso.open("r", encoding="utf-8") as file:
for numero_riga, riga in enumerate(file, start=1):
totale_righe += 1
riga = riga.strip()
if "ERROR" in riga:
numero_errori += 1
if parola_chiave.lower() in riga.lower():
righe_trovate.append((numero_riga, riga))
return {
"totale_righe": totale_righe,
"numero_errori": numero_errori,
"righe_trovate": righe_trovate,
}
def cerca_prima_occorrenza(percorso: Path, testo_da_trovare: str) -> tuple[int, str] | None:
"""
Cerca la prima riga che contiene il testo richiesto.
Usa un ciclo while per mostrare un controllo manuale dell´iterazione.
"""
righe = percorso.read_text(encoding="utf-8").splitlines()
indice = 0
# Ciclo while: utile quando vogliamo controllare esplicitamente l´indice
while indice < len(righe):
riga = righe[indice]
if testo_da_trovare.lower() in riga.lower():
return indice + 1, riga
indice += 1
return None
def stampa_report(risultati: dict) -> None:
print("=== REPORT ANALISI FILE ===")
print(f"Totale righe: {risultati[´totale_righe´]}")
print(f"Righe con ERROR: {risultati[´numero_errori´]}")
print("Righe che contengono la parola chiave:")
for numero_riga, testo in risultati["righe_trovate"]:
print(f" - Riga {numero_riga}: {testo}")
def main() -> None:
file_log = Path("esempio_log.txt")
crea_file_di_esempio(file_log)
risultati = analizza_log(file_log, parola_chiave="servizio")
stampa_report(risultati)
ricerca = cerca_prima_occorrenza(file_log, "Timeout")
if ricerca is not None:
numero_riga, testo = ricerca
print("nPrima occorrenza trovata:")
print(f"Riga {numero_riga}: {testo}")
else:
print("nNessuna occorrenza trovata.")
if __name__ == "__main__":
main() Spiegazione
Vediamo il programma pezzo per pezzo. Il file di esempio contiene righe di log con livelli diversi: INFO, WARNING ed ERROR. Questo tipo di struttura è molto comune nei sistemi reali, perché permette di registrare eventi e diagnosticare problemi.
1. Creazione del file di esempio
La funzione crea_file_di_esempio scrive un piccolo file di testo. È utile per testare il codice senza dover preparare manualmente un file esterno ogni volta. In un progetto reale questa funzione non servirebbe necessariamente, ma è perfetta per esercitarsi.
2. Lettura con for
La funzione analizza_log usa un ciclo for per leggere il file riga per riga:
- enumerate(file, start=1) restituisce sia il numero di riga sia il contenuto.
- strip() rimuove spazi e a capo inutili.
- La condizione "ERROR" in riga incrementa il contatore degli errori.
- La ricerca della parola chiave usa un confronto case-insensitive con lower().
Questo approccio è molto efficiente perché non carica tutto il file in una struttura complessa: il ciclo scorre le righe in modo naturale e leggibile.
3. Ricerca con while
La funzione cerca_prima_occorrenza mostra un uso diverso del ciclo while. Qui non stiamo iterando “automaticamente” su un oggetto iterabile, ma gestiamo noi l’indice indice.
Il ciclo continua finché indice < len(righe). Ad ogni iterazione controlla la riga corrente e, se trova il testo richiesto, restituisce subito il risultato con return. Questo è un caso d’uso utile quando serve un controllo più esplicito del flusso.
4. Produzione del report
La funzione stampa_report mostra come presentare i dati raccolti. Anche qui troviamo un ciclo for, ma questa volta serve a stampare l’elenco delle righe trovate. È un esempio semplice ma realistico di separazione delle responsabilità: una funzione analizza, un’altra stampa.
5. Funzione main
La funzione main coordina l’intero processo: crea il file, lo analizza, stampa il report e cerca una prima occorrenza specifica. Questa struttura rende il programma più ordinato e facile da estendere.
Best practice
Quando usi cicli for e while per elaborare file o dati testuali, alcune buone pratiche fanno davvero la differenza:
- Usa for quando scorre un iterabile: file, liste, tuple e generatori sono casi ideali.
- Usa while quando controlli manualmente una condizione: per esempio un indice, un tentativo di ricerca o una ripetizione legata a uno stato.
- Apri i file con with: garantisce la chiusura automatica della risorsa, anche in caso di errore.
- Evita di caricare file enormi in memoria se non serve: iterare direttamente sul file è spesso più efficiente.
- Normalizza il testo con strip(), lower() o upper() quando fai confronti.
- Separa logica e output: una funzione per analizzare, una per stampare, una per orchestrare.
- Usa nomi chiari per variabili e funzioni: il codice diventa più facile da mantenere.
Un altro consiglio importante: se devi fermarti appena trovi un valore, while o for con return possono essere perfetti. Se invece devi esaminare tutto il contenuto, il for è spesso la scelta più naturale.
Riepilogo
In questo tutorial abbiamo visto un sotto-argomento molto pratico: l’uso di for e while per elaborare file di testo. Il ciclo for è ideale per scorrere le righe in modo semplice e leggibile, mentre il ciclo while è utile quando vuoi controllare direttamente l’avanzamento dell’iterazione.
Abbiamo anche costruito un esempio concreto che:
- crea un file di log di esempio;
- conta le righe e gli errori;
- cerca righe contenenti una parola chiave;
- trova la prima occorrenza di un testo specifico;
- stampa un report finale in modo ordinato.
Questo tipo di approccio è molto comune in automazione, analisi dati e manutenzione di piccoli tool Python. Padroneggiare bene i cicli significa scrivere codice più robusto, più chiaro e più utile nella pratica.
Approfondisci con risorse ufficiali
- Python Tutorial - Control Flow Tools: documentazione ufficiale sui cicli e sul controllo del flusso.
- Python Tutorial - Reading and Writing Files: guida ufficiale alla gestione dei file.
- Built-in Functions: approfondimento su enumerate(), len(), print() e altre funzioni integrate.
- pathlib: modulo moderno e consigliato per lavorare con percorsi e file.
Consulta la documentazione ufficiale di Python per consolidare questi concetti e scoprire varianti più avanzate, come l’uso di generatori, espressioni condizionali e gestione degli errori durante la lettura dei file.
