Un programma Python può contenere funzioni riutilizzabili e, allo stesso tempo, comportarsi come uno script eseguibile. La condizione if __name__ == "__main__": serve proprio a separare questi due comportamenti, evitando che operazioni come stampe, chiamate API o connessioni al database partano automaticamente durante un import. In questa guida mostro come funziona, quando usarla e come applicarla a uno script con SQLite.
La regola che separa codice riutilizzabile ed esecuzione diretta
- Esecuzione diretta significa avviare il file con Python e attivare il blocco principale.
- Durante un import, __name__ contiene il nome del modulo, non
__main__. - Il blocco protetto evita effetti collaterali indesiderati quando il file viene importato.
- La funzione
main()è una convenzione utile, non una parola riservata di Python. - Con SQLite è buona pratica aprire la connessione solo nel flusso principale.
Che cosa controlla davvero __name__
Ogni modulo Python possiede una variabile speciale chiamata __name__. Quando lancio direttamente un file, l’interprete assegna a quella variabile il valore __main__; quando invece importo lo stesso file, usa il nome del modulo.
La condizione confronta quindi due stringhe. Se il confronto è vero, Python esegue il codice indentato sotto l’if; se è falso, quel blocco viene saltato. Il resto del file, comprese le definizioni di funzioni e classi, può comunque essere caricato.
def saluta():
return "Ciao dal modulo"
if __name__ == "__main__":
print(saluta())Avviando il file con python saluto.py, vedo il messaggio nel terminale. Se scrivo invece import saluto da un altro programma, la funzione viene resa disponibile ma il print non parte. È questa distinzione a rendere il file sia eseguibile sia riutilizzabile.
Che differenza c’è tra avvio diretto e importazione
Il comportamento diventa più chiaro osservando i tre casi più comuni. La differenza non riguarda soltanto la visualizzazione di un messaggio: può determinare se vengono eseguite query, creati file o aperte connessioni esterne.
| Modalità | Valore di __name__
|
Blocco principale |
|---|---|---|
python script.py |
__main__ |
Viene eseguito |
import script |
script |
Non viene eseguito |
python -m pacchetto.script |
__main__ |
Viene eseguito |
Durante un import, Python esegue comunque le istruzioni presenti al livello superiore del modulo. Per questo considero rischioso inserire direttamente fuori dal blocco protetto operazioni come scritture su database, richieste HTTP o cancellazioni di file.
Il controllo non blocca l’importazione dell’intero file e non crea una sandbox. Protegge soltanto le istruzioni contenute nel blocco condizionale, lasciando disponibili le funzioni e le classi che servono agli altri moduli.
Perché conviene chiamare una funzione main
Per un esempio di due righe si potrebbe inserire direttamente il codice sotto la condizione. Nei progetti reali preferisco però definire una funzione main() e usarla come punto di ingresso, perché il flusso diventa più leggibile e più semplice da testare.
def main():
nome = input("Come ti chiami? ")
print(f"Ciao, {nome}!")
return 0
if __name__ == "__main__":
raise SystemExit(main())In questo schema main() restituisce un codice di uscita. Il valore 0 indica normalmente un’esecuzione riuscita, mentre un numero diverso da zero può segnalare un errore a uno script di shell, a una pipeline CI/CD o a un orchestratore cloud.
La funzione non deve chiamarsi per forza main. Il nome è una convenzione molto diffusa, utile perché comunica immediatamente il ruolo della funzione. Il vero elemento che controlla l’avvio è il confronto tra __name__ e __main__.
Un esempio pratico con SQLite
Il caso dei database mostra bene il vantaggio del costrutto. Immagino un modulo che contiene una funzione per creare una tabella e una funzione principale che apre il database, inserisce un record e chiude la connessione.
import sqlite3
def crea_tabella(connessione):
connessione.execute("""
CREATE TABLE IF NOT EXISTS utenti (
id INTEGER PRIMARY KEY,
nome TEXT NOT NULL
)
""")
def inserisci_utente(connessione, nome):
connessione.execute(
"INSERT INTO utenti (nome) VALUES (?)",
(nome,)
)
def main():
with sqlite3.connect("archivio.db") as connessione:
crea_tabella(connessione)
inserisci_utente(connessione, "Luca")
print("Utente salvato")
if __name__ == "__main__":
raise SystemExit(main())Se eseguo il file direttamente, SQLite crea o aggiorna archivio.db. Se importo il modulo per riutilizzare inserisci_utente() in un’applicazione web, il database non viene modificato automaticamente. Per me questo è il punto più importante: le funzioni descrivono le operazioni, mentre main() decide quando eseguirle.
Nel codice uso i segnaposto ? invece di concatenare stringhe SQL. È una scelta essenziale per evitare SQL injection e per gestire correttamente valori contenenti apostrofi o caratteri speciali. Il guard clause non sostituisce le buone pratiche del database, ma impedisce che una semplice importazione avvii operazioni non richieste.
Gli errori che fanno inciampare più spesso
Confondere una variabile normale con quella speciale
La forma corretta usa due underscore prima e dopo i nomi: __name__ e __main__. Scrivere una variante con un solo underscore crea un controllo diverso e generalmente non produce il comportamento atteso.
Chiamare main prima di definirla
Python esegue le istruzioni dall’alto verso il basso. Se il blocco finale chiama main() prima che la funzione sia stata definita, ottengo un NameError. Tengo quindi definizioni e funzioni sopra il punto di ingresso.
Mettere effetti collaterali fuori dal blocco
Importare una libreria standard, definire una costante o dichiarare una funzione è normalmente innocuo. Aprire una connessione, modificare una tabella o lanciare un processo esterno è diverso: queste operazioni dovrebbero partire dentro main() o dentro una funzione chiamata esplicitamente.
Leggi anche: API informatiche - come funzionano e quale approccio scegliere
Pensare che il blocco protegga ogni importazione
Il contenuto al livello superiore viene comunque valutato durante l’import. Se un modulo importato a sua volta contiene codice operativo fuori dal proprio blocco principale, quel codice può partire. Quando qualcosa si comporta in modo inatteso, controllo quindi tutta la catena degli import, non soltanto il file che sto eseguendo.
Come usarlo bene in test e progetti più grandi
Separare la logica dalle operazioni di avvio rende i test più semplici. Posso importare una funzione, passarle dati fittizi e verificare il risultato senza simulare ogni volta l’avvio da terminale o la configurazione completa dell’applicazione.
Nei progetti più strutturati, mantengo nel modulo principale soltanto un avvio leggero e sposto la logica in funzioni dedicate. Per esempio, una funzione può leggere gli argomenti, una può validare i dati e una può gestire la persistenza. Questa divisione riduce il rischio che un test apra davvero un database di produzione.
Quando lo script cresce, conviene aggiungere strumenti come argparse per gli argomenti da riga di comando e registrare gli errori in modo esplicito. La condizione di ingresso resta utile, ma non deve diventare un contenitore di cinquanta istruzioni difficili da mantenere.
Il punto di ingresso che mantiene il codice sotto controllo
La regola pratica è semplice: definisco funzioni e classi riutilizzabili, raccolgo l’avvio in main() e chiamo quella funzione soltanto quando il file viene eseguito direttamente. In questo modo importazioni, test, script automatici e operazioni sul database restano separati e prevedibili.
Non è una formula magica né un obbligo imposto dal linguaggio. È una convenzione piccola, ma con un effetto concreto sulla qualità del codice: riduce le sorprese, chiarisce il flusso di esecuzione e lascia aperta la strada alla trasformazione di uno script in un modulo vero e proprio.