Introduzione
Un modulo Python può svolgere due ruoli diversi: può essere importato da altri moduli oppure può essere eseguito direttamente come programma. Gestire correttamente questa doppia modalità è molto utile nei progetti reali, perché permette di riutilizzare il codice senza duplicarlo e di mantenere separata la logica dell’applicazione dall’avvio del programma.
La tecnica fondamentale consiste nell’usare la variabile speciale __name__ insieme alla condizione if __name__ == "__main__":. In questo modo, una parte del modulo viene eseguita soltanto quando il file è avviato direttamente, ma non quando viene importato.
Inoltre, nei progetti organizzati come pacchetti, il comando python -m consente di eseguire un modulo rispettando la struttura del package e il contesto degli import. Questa soluzione è generalmente più affidabile dell’avvio diretto con python percorso/file.py.
Codice completo
Creiamo il seguente progetto:
progetto_report/
├── report_app/
│ ├── __init__.py
│ ├── statistiche.py
│ └── cli.py
└── tests_demo.py Il modulo statistiche.py contiene la logica riutilizzabile:
# report_app/statistiche.py
def media(valori):
"""Calcola la media di una sequenza di numeri."""
if not valori:
raise ValueError("La sequenza non può essere vuota")
return sum(valori) / len(valori)
def riepilogo(valori):
"""Restituisce alcune statistiche di base."""
return {
"minimo": min(valori),
"massimo": max(valori),
"media": media(valori),
} Il modulo cli.py offre invece un’interfaccia eseguibile:
# report_app/cli.py
from .statistiche import riepilogo
def mostra_report(valori):
"""Stampa il report in un formato leggibile."""
dati = riepilogo(valori)
print("Report delle vendite")
print("--------------------")
print(f"Valori analizzati: {len(valori)}")
print(f"Minimo: {dati[´minimo´]:.2f}")
print(f"Massimo: {dati[´massimo´]:.2f}")
print(f"Media: {dati[´media´]:.2f}")
def main():
"""Punto di ingresso dell´applicazione."""
vendite = [120.50, 98.00, 175.25, 143.90]
mostra_report(vendite)
# Questa funzione viene chiamata solo con l´esecuzione diretta.
if __name__ == "__main__":
main() Il file __init__.py può identificare il package senza eseguire codice applicativo:
# report_app/__init__.py
__version__ = "1.0.0" Per eseguire il programma dalla cartella progetto_report, usiamo:
python -m report_app.cli È possibile importare la funzione senza avviare automaticamente il report:
# tests_demo.py
from report_app.cli import mostra_report
dati = [10, 20, 30]
mostra_report(dati) Spiegazione
Il significato di __name__
Python assegna a ogni modulo una variabile speciale chiamata __name__. Quando un file viene importato, il suo valore è normalmente il nome del modulo, per esempio report_app.cli. Quando invece il file viene eseguito direttamente come programma, il valore diventa __main__.
La condizione:
if __name__ == "__main__":
main() permette quindi di distinguere i due casi. Le definizioni di funzioni e classi vengono caricate durante l’import, mentre main() viene chiamata soltanto durante l’avvio del programma.
Perché usare python -m
Il comando python -m report_app.cli dice all’interprete di cercare ed eseguire il modulo cli all’interno del package report_app. Questo approccio mantiene disponibile il contesto del pacchetto e rende più naturali gli import relativi, come:
from .statistiche import riepilogo Con il comando diretto:
python report_app/cli.py l’import relativo può generare un errore, perché il file non viene trattato come parte di un package. Per questo, nei progetti strutturati, python -m è spesso la scelta preferibile.
Separare logica e avvio
La funzione main() dovrebbe occuparsi principalmente di coordinare l’applicazione: leggere dati, chiamare funzioni e mostrare risultati. La logica di calcolo, invece, dovrebbe rimanere in moduli indipendenti. Questa separazione facilita il riuso, i test e la manutenzione.
Best practice
- Usa sempre una funzione
main(): evita di inserire molte istruzioni operative direttamente nel blocco condizionale. - Proteggi il punto di ingresso: inserisci il codice eseguibile dentro
if __name__ == "__main__":. - Preferisci
python -mnei package: riduce i problemi con gli import relativi. - Non eseguire operazioni pesanti durante l’import: un import dovrebbe principalmente definire funzioni, classi e costanti.
- Mantieni la logica riutilizzabile: le funzioni chiamate da
main()dovrebbero poter essere importate e testate separatamente. - Gestisci gli argomenti in modo esplicito: per programmi più completi puoi usare
argparsedentromain(). - Esegui i comandi dalla radice del progetto: in questo modo Python individua correttamente il package.
Riepilogo
Un modulo Python può essere contemporaneamente una libreria e un programma eseguibile. La variabile __name__ permette di capire in quale modalità il modulo è stato caricato. La condizione if __name__ == "__main__": impedisce che il codice di avvio venga eseguito durante un import.
Nei progetti organizzati in pacchetti, python -m nome_package.nome_modulo è il modo consigliato per eseguire un modulo, soprattutto quando si utilizzano import relativi. Separando la funzione main() dalla logica applicativa si ottiene codice più riutilizzabile, testabile e semplice da mantenere.
