Was ist der Zweck des Schalters -m?

174

Können Sie mir erklären, was der Unterschied zwischen Anrufen ist?

python -m mymod1 mymod2.py args

und

python mymod1.py mymod2.py args

Es scheint in beiden Fällen mymod1.pyheißt und sys.argvist

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

Wofür ist der -mSchalter?

Charles Brunet
quelle
Bitte korrigieren Sie mich, wenn ich falsch liege, aber im Standardbibliothekspfad -mzu suchen scheint mymod1. Beispiel: python -m SimpleHTTPServerfunktioniert, während mit python SimpleHTTPServerscheitert can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory.
Basj
7
Ich fand die Antwort hier tatsächlich klarer: stackoverflow.com/questions/46319694/…
Casebash

Antworten:

137

Die erste Zeile des RationaleAbschnitts von PEP 338 lautet:

Python 2.4 fügt den Befehlszeilenschalter -m hinzu, damit Module mithilfe des Python-Modul-Namespace zur Ausführung als Skripte gefunden werden können. Die motivierenden Beispiele waren Standardbibliotheksmodule wie pdb und profile, und die Python 2.4-Implementierung ist für diesen begrenzten Zweck in Ordnung.

Auf diese Weise können Sie jedes Modul im Python-Suchpfad angeben, nicht nur Dateien im aktuellen Verzeichnis. Sie haben Recht, das python mymod1.py mymod2.py argshat genau den gleichen Effekt. In der ersten Zeile des Scope of this proposalAbschnitts heißt es:

In Python 2.4 wird ein Modul mit -m so ausgeführt, als ob sein Dateiname in der Befehlszeile angegeben worden wäre.

Mit -mmehr ist möglich, wie mit Modulen zu arbeiten, die Teil eines Pakets sind usw. Darum geht es im Rest von PEP 338. Lesen Sie es für weitere Informationen.

agf
quelle
47
Meine Lieblingsverwendung von -mist python -m SimpleHTTPServer. Sehr praktisch, wenn ich einige Dateien ohne Verwendung eines USB-Flash-Laufwerks freigeben muss.
Arifwn
21
@arifwn Das Ausführen von Python3 erfordert ein kleines Update, da python -m http.serverdies immer noch fantastisch ist!
Kit Roed
12
TL; DR: 1) Sie können ausführen python -m package.subpackage.moduleund die normale Auflösungsmaschine wird verwendet, Sie müssen nicht auf die genaue .pyDatei hinweisen . 2) Es ist möglich, relative Importe aus dem ausgeführten Modul ohne Problemumgehungen durchzuführen, da das Paket unterwegs geladen wird. 3) Absolute Importe basieren auf Ihrem aktuellen Verzeichnis, nicht auf dem Verzeichnis, in dem sich die .pyDatei befindet ( ''befindet sich am Anfang von sys.pathund nicht /path/to/my, wenn sich das Skript befindet /path/to/my/script.py).
Clacke
Was diese Antwort nicht klar macht, ist, dass dies nur für die Teilmenge der Module funktioniert, die ausführbar sind, dh eine __main__.pyDatei haben. Die meisten nicht und werden brechen, zB python -m sys 'print(sys.version)'scheitert mit python: No code object available for sys. Schlagen Sie vor, dass Sie dies in der Antwort klarstellen.
smci
19

Erwähnenswert ist, dass dies nur funktioniert, wenn das Paket eine Datei enthält.__main__.py Andernfalls kann dieses Paket nicht direkt ausgeführt werden.

python -m some_package some_arguments

Der Python-Interpreter sucht im Paketpfad nach einer __main__.pyDatei, die ausgeführt werden soll. Es ist äquivalent zu:

python path_to_package/__main__.py somearguments

Der Inhalt wird ausgeführt nach:

if __name__ == "__main__":
Marquez.Z
quelle
2
Was ist mit der Paket-Init-Datei? Wird bei Vorhandensein der Hauptdatei auch init aufgerufen?
Variable
@variable Ja init .py wird aufgerufen, bevor main .py aufgerufen wird
Mark Rucker vor
1

Obwohl diese Frage mehrmals gestellt und beantwortet wurde (z. B. hier , hier , hier und hier ), erfasst meiner Meinung nach keine vorhandene Antwort alle Implikationen der -mFlagge vollständig oder präzise . Daher wird im Folgenden versucht, das bisherige zu verbessern.

TLDR

Der -mBefehl erledigt viele Dinge, die nicht unbedingt immer benötigt werden. Kurz gesagt: (1) ermöglicht die Ausführung von Python-Skripten über den Modulnamen anstelle des Dateinamens. (2) ermöglicht die Auswahl eines Verzeichnisses, das sys.pathzur importAuflösung hinzugefügt werden soll, und (3) ermöglicht, dass Python-Skripte mit relativen Importen so funktionieren, als ob sie es wären angerufen über import.

Vorbereitungen

Um die Bedeutung der -mFlagge zu verstehen , muss eine kleine Terminologie klargestellt werden.

Erstens werden Dateien, die Python ausführen kann, als Module bezeichnet. Normalerweise sind die Module, die uns interessieren, *.pyDateien, aber nicht immer. Beispielsweise ist es möglich, Python-Module für leistungskritischen Code in C zu schreiben. Diese Unterscheidung wird später wichtig. Im Moment reicht es zu wissen, dass Nicht-Paket-Module Dateien sind.

Zweitens identifiziert Python Module über eine eindeutige <modulename>Kennung (z import <modulename>. B. ). Für jedes Unikat <modulename>gibt es auch irgendwo auf dem Computer eine eindeutige Datei mit einem eigenen Unikat <filename>. Python Dolmetscher folgen einer Reihe von gut definierten Regeln gebaut um sys.patheine zur Karte <modulename>zu einem <filename>(mehr darüber , wie dies geschehen ist , siehe PEP 302 ).

Historische Entwicklung von -m

Mit Blick auf die Vorbereitungen -mkann im einfachsten Sinne erklärt werden, dass Python angewiesen wird, ein Modul zu finden, über das ausgeführt werden soll, <modulename>anstatt <filename>. Das heißt, wenn entweder ein <filename>oder <modulename>für dasselbe Modul gegeben ist, sind die folgenden zwei Befehle äquivalent python <filename>oder python -m <modulename>.

In der ursprünglichen Version 2.4.1, in -mder hinzugefügt wurde, wurden lediglich Module von gesucht und ausgeführt <modulename>(wobei zusätzlich das aktuelle Verzeichnis hinzugefügt wurde, sys.pathdamit auch lokale Module gefunden werden konnten). Gemäß PEP 338 wurde auch die ursprüngliche Implementierung eingeschränkt, so dass -mkeine Modulnamen in Paketen referenziert werden konnten (dh die Version 2.4.1 würde den Modulnamen nicht unterstützen, http.serveraber unterstützen timeit).

Mit PEP 338 wurde die -mFunktionalität erweitert, um <modulename>Darstellungen in Paketen zu unterstützen. Dies bedeutete Namen, wie http.serversie jetzt vollständig von unterstützt wurden -m. Diese Erweiterung bedeutet auch , dass alle Pakete in einem Modulnamen geladen werden mußten (dh die Pakete __init__.pywurden Dateien ausgeführt), zusammen mit dem Modul selbst, falls die Pakete ihr modifizierten __path__in __init__.py.

Ein bemerkenswerter Anwendungsfall, der -mnach PEP 338 unterstützt wurde, waren absolute Importanweisungen in benutzerdefinierten Paketen, ohne dass ein Paket installiert werden musste sys.path. Dies kann erreicht werden, indem einfach -mSkriptdateien aus dem Stammverzeichnis des benutzerdefinierten Projekts geladen werden (da das Stammverzeichnis dann hinzugefügt wird sys.path).

Die letzte wichtige Funktionserweiterung für -mkam mit PEP 366 . Mit diesem Update wurde -mdie Möglichkeit gewonnen, nicht nur absolute Importe, sondern auch explizite relative Importe zu unterstützen. Dies wurde erreicht, indem die __package__Variable für das benannte Modul im -mBefehl geändert wurde.

Mit all den oben genannten Verbesserungen -mweist es immer noch ein großes Manko auf. Es können nur Module ausgeführt werden, die in Python (dh *.py) geschrieben sind. Wenn ein Modulname, der sich auf ein C-kompiliertes Modul bezieht, an -mden folgenden Fehler übergeben wird , wird der folgende Fehler erzeugt No code object available for <modulename>.

Vergleich -mmit anderen Ausführungsmethoden

Im Kern ist das -mFlag ein Mittel, um Python-Skripte über den Modulnamen und nicht über den Dateinamen auszuführen. Aus diesem Grund vergleichen wir es mit den beiden anderen bekannteren Methoden zur Ausführung von Modulen: (1) Dateiname mit dem pythonBefehl und (2) Modulname mit der importAnweisung.

Auswirkungen der Dateinamenausführung mit dem pythonBefehl (dh python <filename>):

  1. Pythons wurde sys.pathso geändert, dass der Speicherort des Moduls in die Importauflösung einbezogen wird
  2. Die __name__Variable des Moduls ist auf gesetzt'__main__'
  3. Die __package__Variable des Moduls ist auf gesetztNone
  4. __init__.pyFür übergeordnete Pakete in werden keine Dateien ausgeführt<filename>

Auswirkungen der Ausführung von Modulnamen mit der importAnweisung (dh import <modulename>):

  1. Python sys.pathist nicht für den Import Auflösung in keiner Weise verändert
  2. Die __name__Variable des Moduls wird auf ihren absoluten Modulnamen gesetzt
  3. Die __package__Variable des Moduls wird auf das enthaltende Paket in gesetzt<modulename>
  4. Alle __init__.pyDateien werden für übergeordnete Pakete in ausgeführt<modulename>

Auswirkungen der Ausführung von Modulnamen mit dem -mFlag (dh python -m <modulename>):

  1. Pythons wurde sys.pathso geändert, dass das aktuelle Verzeichnis in die Importauflösung aufgenommen wird
  2. Die __name__Variable des Moduls ist auf gesetzt'__main__'
  3. Die __package__Variable des Moduls wird auf das enthaltende Paket in gesetzt<modulename>
  4. Alle __init__.pyDateien werden für übergeordnete Pakete in ausgeführt<modulename>

Zusammenfassung

Das -mFlag ist einfach eine alternative Möglichkeit, ein Python-Skript über den Modulnamen und nicht über den Dateinamen auszuführen. Aus diesem Grund muss man zumindest ein kleines Verständnis dafür haben, wie Python Modulnamen Dateinamen zuordnet, um sie voll ausnutzen zu können. Mit diesem Verständnis erhält man jedoch ein leistungsstarkes neues Tool, das Funktionen von importAnweisungen (z. B. Unterstützung für explizite relative Importanweisungen) mit der Bequemlichkeit von Befehlszeilenanweisungen kombiniert python.

Mark Rucker
quelle
Könnten Sie auch die Verwendung des aufrufenden Pakets hinzufügen, indem Sie Folgendes verwendenpython -m packagename : stackoverflow.com/a/53772635/1779091
Variable vor