Qual è lo scopo dell'opzione -m?


174

Potresti spiegarmi qual è la differenza tra chiamare

python -m mymod1 mymod2.py args

e

python mymod1.py mymod2.py args

Sembra in entrambi i casi che mymod1.pysi chiama ed sys.argvè

['mymod1.py', 'mymod2.py', 'args']

A cosa serve l' -minterruttore?


Per favore, correggimi se sbaglio, ma -msembra cercare mymod1nel percorso di libreria predefinito. Esempio: python -m SimpleHTTPServerfunziona, mentre python SimpleHTTPServerfallisce con can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory.
Basj

7
In realtà ho trovato la risposta qui più chiaro: stackoverflow.com/questions/46319694/...
Casebash

Risposte:


137

La prima riga della Rationalesezione di PEP 338 dice:

Python 2.4 aggiunge l'opzione della riga di comando -m per consentire ai moduli di essere localizzati usando lo spazio dei nomi del modulo Python per l'esecuzione come script. Gli esempi motivanti sono stati i moduli di libreria standard come pdb e profile, e l'implementazione di Python 2.4 va bene per questo scopo limitato.

Quindi puoi specificare qualsiasi modulo nel percorso di ricerca di Python in questo modo, non solo i file nella directory corrente. Hai ragione che python mymod1.py mymod2.py argsha esattamente lo stesso effetto. La prima riga della Scope of this proposalsezione indica:

In Python 2.4, un modulo localizzato usando -m viene eseguito proprio come se il suo nome file fosse stato fornito sulla riga di comando.

Con -mpiù è possibile, come lavorare con moduli che fanno parte di un pacchetto, ecc. Questo è il resto del PEP 338. Leggi per maggiori informazioni.


47
Il mio uso preferito di -mè python -m SimpleHTTPServer. Davvero utile quando devo condividere alcuni file senza usare una chiavetta USB.
generato il

21
@arifwn L'esecuzione di Python3 richiede un leggero aggiornamento python -m http.servere questo è ancora fantastico!
Kit Roed

12
TL; DR: 1) È possibile eseguire python -m package.subpackage.modulee verrà utilizzato il normale macchinario di risoluzione, non è necessario indicare il .pyfile esatto . 2) È possibile effettuare importazioni relative dal modulo in esecuzione, senza soluzioni alternative, poiché il suo pacchetto verrà caricato lungo il percorso. 3) Le importazioni assolute si baseranno sulla tua directory corrente, non sulla directory in cui si trova il .pyfile ( ''è all'inizio sys.path, piuttosto che /path/to/my, se lo script è su /path/to/my/script.py).
clacke,

Ciò che questa risposta non chiarisce è che funziona solo sul sottoinsieme di moduli che sono eseguibili, cioè hanno un __main__.pyfile. La maggior parte non lo fa e si romperà, ad es. python -m sys 'print(sys.version)'Fallisce python: No code object available for sys. Suggerisci di chiarirlo nella risposta.
smci

19

Vale la pena ricordare che funziona solo se il pacchetto ha un file__main__.py Altrimenti, questo pacchetto non può essere eseguito direttamente.

python -m some_package some_arguments

L'interprete python cercherà un __main__.pyfile nel percorso del pacchetto da eseguire. È equivalente a:

python path_to_package/__main__.py somearguments

Eseguirà il contenuto dopo:

if __name__ == "__main__":

2
E il file init del pacchetto? In presenza del file principale, verrà invocato anche init?
variabile dal

@variabile Sì. init .py verrà invocato prima che venga invocato il .py principale
Mark Rucker,

1

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 -mbandiera. Pertanto, quanto segue tenterà di migliorare ciò che è accaduto prima.

Introduzione (TLDR)

Il -mcomando 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.pathper la importrisoluzione e (3) consente l'esecuzione degli script Python con relative importazioni dalla riga di comando .

Preliminari

Per spiegare la -mbandiera 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 *.pyfile mentre il tipo più comune di moduli di pacchetto sono le directory che contengono un __init__.pyfile.

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.pathvariabile 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__.pysarà valutata seguito <filename>/__main__.py. D'altra parte, se uno esegue lo stesso modulo pacchetto tramite import <modulename>, __init__.pyverranno 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 -mfunzionato 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 -mfunzionalità è stata estesa per supportare <modulename>rappresentazioni oltre i nomi dei moduli di livello superiore. Ciò significava che nomi come quelli http.servererano ora pienamente supportati. Questo miglioramento ha comportato anche il caricamento di tutti i pacchetti in un modulo (ovvero, __init__.pysono stati valutati tutti i file dei pacchetti ), insieme al modulo stesso.

Il miglioramento finale della funzionalità principale è -marrivato con PEP 366 . Con questo aggiornamento è stata -macquisita 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 -mcomando.

Casi d'uso

Esistono due casi d'uso notevoli per il flag -m:

  1. 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.servermodulo 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.

  2. 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.pathanziché 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 -mcorso degli anni ha ancora un grosso difetto: può eseguire solo moduli di codice scritti in python (cioè, * .py). Ad esempio, se -mviene 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__.pyviene 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.pathnon 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__.pynon 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__.pyviene valutato per i moduli del pacchetto; il codice viene valutato per i moduli di codice

Conclusione

Il -mflag è, nella sua forma più semplice, un mezzo per eseguire script Python dalla riga di comando usando nomi di moduli anziché nomi di file. Inoltre, -mfornisce funzionalità aggiuntive che combinano la potenza delle importistruzioni (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.


Potresti anche aggiungere l'uso del pacchetto di invocazione usando python -m packagenamecome menzionato qui: stackoverflow.com/a/53772635/1779091
variabile

@Variabile buona idea, ho aggiunto una sezione "Caso d'uso" che lo include.
Mark Rucker,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.