Nonostante questa domanda sia stata posta e risposta più volte (ad esempio, qui , qui , qui e qui ) secondo me nessuna risposta esistente cattura in modo completo o conciso tutte le implicazioni della -m
bandiera. Pertanto, quanto segue tenterà di migliorare ciò che è accaduto prima.
Introduzione (TLDR)
Il -m
comando fa molte cose e non tutte saranno necessariamente necessarie per tutto il tempo. In breve: (1) consente l'esecuzione degli script Python tramite modulename anziché il nome file (2) consente di scegliere una directory da aggiungere sys.path
per la import
risoluzione e (3) consente l'esecuzione degli script Python con relative importazioni dalla riga di comando .
Preliminari
Per spiegare la -m
bandiera dobbiamo prima chiarire un po 'di terminologia.
Innanzitutto, l'unità organizzativa principale di Python è nota come modulo . Il modulo è disponibile in due modi: moduli di codice e moduli pacchetto. Un modulo di codice è qualsiasi file che contiene codice eseguibile python. Un modulo pacchetto è una directory che contiene altri moduli (moduli di codice o moduli di pacchetto). Il tipo più comune di moduli di codice sono i *.py
file mentre il tipo più comune di moduli di pacchetto sono le directory che contengono un __init__.py
file.
In secondo luogo, tutti i moduli possono essere identificati in modo univoco in due modi distinti: <modulename>
e <filename>
. I moduli sono spesso identificati dal nome modulo nel codice Python (ad esempio, import <modulename>
) e dal nome file sulla riga di comando (ad esempio, python <filename>
). Tutti gli interpreti Python possono convertire i nomi dei moduli in nomi di file tramite una serie di regole ben definite. Queste regole dipendono dalla sys.path
variabile e quindi la mappatura può essere modificata cambiando questo valore (per ulteriori informazioni su come farlo, consultare PEP 302 ).
In terzo luogo, tutti i moduli (sia codice che pacchetto) possono essere eseguiti (con questo intendiamo che il codice associato al modulo sarà valutato dall'interprete Python). A seconda del metodo di esecuzione e del tipo di modulo, quale codice viene valutato e quando, può cambiare un po '. Ad esempio, se si esegue un modulo pacchetto tramite python <filename>
allora <filename>/__init__.py
sarà valutata seguito <filename>/__main__.py
. D'altra parte, se uno esegue lo stesso modulo pacchetto tramite import <modulename>
, __init__.py
verranno eseguiti solo i pacchetti .
Sviluppo storico di -m
Il flag -m è stato introdotto per la prima volta in Python 2.4.1 . Inizialmente il suo unico scopo era fornire un mezzo alternativo per identificare un modulo Python da eseguire. Cioè, se sapessimo sia l' <filename>
e <modulename>
per un modulo poi i seguenti due comandi sono equivalenti: python <filename> <args>
e python -m <modulename> <args>
. Inoltre, secondo PEP 338 questa iterazione ha -m
funzionato solo con nomi di moduli di livello superiore (ovvero moduli che possono essere trovati direttamente su sys.path senza alcun pacchetto intermedio).
Con il completamento di PEP 338 la -m
funzionalità è stata estesa per supportare <modulename>
rappresentazioni oltre i nomi dei moduli di livello superiore. Ciò significava che nomi come quelli http.server
erano ora pienamente supportati. Questo miglioramento ha comportato anche il caricamento di tutti i pacchetti in un modulo (ovvero, __init__.py
sono stati valutati tutti i file dei pacchetti ), insieme al modulo stesso.
Il miglioramento finale della funzionalità principale è -m
arrivato con PEP 366 . Con questo aggiornamento è stata -m
acquisita la capacità di supportare non solo importazioni assolute ma anche importazioni relative esplicite. Ciò è stato ottenuto modificando la __package__
variabile per il modulo denominato nel -m
comando.
Casi d'uso
Esistono due casi d'uso notevoli per il flag -m:
Per eseguire i moduli dalla riga di comando per i quali è possibile che non si conosca il loro nome file. Questo caso d'uso sfrutta il fatto che l'interprete Python sa come convertire i nomi dei moduli in nomi di file. Ciò è particolarmente vantaggioso quando si desidera eseguire moduli stdlib o moduli di terze parti dalla riga di comando. Ad esempio, pochissime persone conoscono il nome file per il http.server
modulo ma la maggior parte delle persone conosce il suo nome modulo in modo da poterlo eseguire dalla riga di comando utilizzando python -m http.server
.
Per eseguire un pacchetto locale contenente importazioni assolute senza la necessità di installarlo. Questo caso d'uso è dettagliato in PEP 338 e sfrutta il fatto che la directory di lavoro corrente viene aggiunta sys.path
anziché la directory del modulo. Questo caso d'uso è molto simile all'uso pip install -e .
di installare un pacchetto in modalità di sviluppo / modifica.
carenze
Con tutti i miglioramenti apportati nel -m
corso degli anni ha ancora un grosso difetto: può eseguire solo moduli di codice scritti in python (cioè, * .py). Ad esempio, se -m
viene utilizzato per eseguire un modulo di codice compilato in C, verrà prodotto il seguente errore No code object available for <modulename>
(vedere qui per maggiori dettagli).
Confronti dettagliati
Effetti dell'esecuzione del modulo tramite comando python (cioè, python <filename>
):
sys.path
viene modificato per includere la directory finale in <filename>
__name__
è impostato per '__main__'
__package__
è impostato per None
__init__.py
non viene valutato per nessun pacchetto (incluso il suo per i moduli pacchetto)
__main__.py
viene valutato per i moduli del pacchetto; il codice viene valutato per i moduli di codice.
Effetti dell'esecuzione del modulo tramite dichiarazione di importazione (ad es. import <modulename>
):
sys.path
non viene modificato in alcun modo
__name__
è impostato sulla forma assoluta di <modulename>
__package__
è impostato sul pacchetto genitore immediato in <modulename>
__init__.py
viene valutato per tutti i pacchetti (incluso il proprio per i moduli pacchetto)
__main__.py
non viene valutato per i moduli del pacchetto; il codice viene valutato per i moduli di codice
Effetti dell'esecuzione del modulo tramite -m flag (cioè, python -m <modulename>
):
sys.path
viene modificato per includere la directory corrente
__name__
è impostato per '__main__'
__package__
è impostato sul pacchetto genitore immediato in <modulename>
__init__.py
viene valutato per tutti i pacchetti (incluso il proprio per i moduli pacchetto)
__main__.py
viene valutato per i moduli del pacchetto; il codice viene valutato per i moduli di codice
Conclusione
Il -m
flag è, nella sua forma più semplice, un mezzo per eseguire script Python dalla riga di comando usando nomi di moduli anziché nomi di file. Inoltre, -m
fornisce funzionalità aggiuntive che combinano la potenza delle import
istruzioni (ad esempio, il supporto per le importazioni relative esplicite e la __init__
valutazione automatica dei pacchetti ) con la comodità della riga di comando di Python.
-m
sembra cercaremymod1
nel percorso di libreria predefinito. Esempio:python -m SimpleHTTPServer
funziona, mentrepython SimpleHTTPServer
fallisce concan't open file 'SimpleHTTPServer': [Errno 2] No such file or directory
.