Eseguire moduli Python come programmi con <code>python -m</code>

by theArchitect
SHARE
Eseguire moduli Python come programmi con <code>python -m</code>
© Guida-HTML5.it

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 -m nei 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 argparse dentro main().
  • 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.

Approfondisci con risorse ufficiali

SHARE