Wenn Sie das -m
Befehlszeilenflag verwenden , importiert Python ein Modul oder Paket für Sie und führt es dann als Skript aus. Wenn Sie das -m
Flag nicht verwenden , wird die von Ihnen genannte Datei nur als Skript ausgeführt .
Die Unterscheidung ist wichtig, wenn Sie versuchen, ein Paket auszuführen. Es gibt einen großen Unterschied zwischen:
python foo/bar/baz.py
und
python -m foo.bar.baz
wie im letzteren Fall foo.bar
wird importiert und relative Importe funktionieren korrekt foo.bar
als Ausgangspunkt.
Demo:
$ mkdir -p test/foo/bar
$ touch test/foo/__init__.py
$ touch test/foo/bar/__init__.py
$ cat << EOF > test/foo/bar/baz.py
> if __name__ == "__main__":
> print __package__
> print __name__
>
> EOF
$ PYTHONPATH=test python test/foo/bar/baz.py
None
__main__
$ PYTHONPATH=test python -m foo.bar.baz
foo.bar
__main__
Infolgedessen muss sich Python bei der Verwendung des -m
Switches tatsächlich um Pakete kümmern . Ein normales Skript kann nie sein ein Paket, so __package__
eingestellt ist None
.
Führen Sie jedoch ein Paket oder Modul in einem Paket mit aus, -m
und jetzt besteht zumindest die Möglichkeit eines Pakets, sodass die __package__
Variable auf einen Zeichenfolgenwert festgelegt wird. In der obigen Demonstration wird festgelegt foo.bar
, dass für einfache Module, die sich nicht in einem Paket befinden, eine leere Zeichenfolge festgelegt wird.
Wie für das __main__
Modul ; Python importiert Skripte, die wie ein reguläres Modul ausgeführt werden. Ein neues Modulobjekt wird erstellt, um den globalen Namespace zu speichern, der in gespeichert ist sys.modules['__main__']
. Darauf __name__
bezieht sich die Variable, sie ist ein Schlüssel in dieser Struktur.
Für Pakete können Sie ein __main__.py
Modul erstellen und dieses beim Ausführen ausführen lassen python -m package_name
. in der Tat , das ist der einzige Weg , Sie können ein Paket als Script ausführen:
$ PYTHONPATH=test python -m foo.bar
python: No module named foo.bar.__main__; 'foo.bar' is a package and cannot be directly executed
$ cp test/foo/bar/baz.py test/foo/bar/__main__.py
$ PYTHONPATH=test python -m foo.bar
foo.bar
__main__
Wenn -m
Python ein Paket zum Ausführen benennt , sucht es nach einem __main__
in diesem Paket enthaltenen Modul und führt dieses als Skript aus. Der Name wird dann weiterhin festgelegt __main__
und das Modulobjekt wird weiterhin gespeichert sys.modules['__main__']
.
PYTHONPATH=test python -m foo.bar
? Könnten Sie es bitte im Detail erklären?PYTHONPATH
eine Umgebungsvariable; Es erweitert die Reihe von Verzeichnissen, in denen Python beim Importieren nach Modulen sucht. Hier wird dastest
Verzeichnis zu dieser Serie hinzugefügt. Wenn Sie es in dieselbe Befehlszeile einfügen, gilt es nur für diesen einzelnenpython
Befehl.-m
Weist Python an, ein bestimmtes Modul zu importieren, als ob Sie es ausgeführt hättenimport foo.bar
. Python führt jedoch automatisch ein__main__
Modul in einem Paket als Skript aus, wenn Sie diesen Schalter verwenden.having to use -m always is not that user-.friendly.
Ich denke, Mixen mit und Nicht-Verwenden-m
ist weniger benutzerfreundlich.-m
Funktioniert nur für das aktuelle Verzeichnis oder die Verzeichnisse, die bereits im Suchpfad registriert sind. Das war mein Punkt.-m
ist nichts, was Sie Endbenutzern für dieses Usability-Problem geben.from Photos import ...
wird sich beschweren. Würde auchimport Photos.<something>
.import Photos
funktioniert nur, weil Python Namespace-Pakete unterstützt (wobei zwei separate DistributionenPhotos.foo
undPhotos.bar
separat bereitgestellt werden und diese unabhängig verwaltet werden können).Ausführung von Python-Code mit der Option -m oder nicht
Verwenden Sie die
-m
Flagge.Die Ergebnisse sind nahezu identisch, wenn Sie ein Skript haben. Wenn Sie jedoch ein Paket ohne
-m
Flag entwickeln, können die Importe nicht ordnungsgemäß ausgeführt werden, wenn Sie ein Unterpaket oder Modul im Paket als Haupteintrag ausführen möchten Zeigen Sie auf Ihr Programm (und glauben Sie mir, ich habe es versucht.)Die Dokumente
Wie die Dokumente auf der Flagge -m sagen:
und
so
ist ungefähr gleichbedeutend mit
(vorausgesetzt, Sie haben kein Paket oder Skript in Ihrem aktuellen Verzeichnis namens pdb.py)
Erläuterung:
Das Verhalten wird "absichtlich ähnlich" zu Skripten gemacht.
Einige Python-Codes sollen als Modul ausgeführt werden: (Ich denke, dieses Beispiel ist besser als das Beispiel für die Befehlszeilenoption doc)
Und aus den Highlights der Versionshinweise für Python 2.4 :
Zusatzfrage
Dies bedeutet, dass jedes Modul, das Sie mit einer Importanweisung nachschlagen können, als Einstiegspunkt des Programms ausgeführt werden kann - wenn es einen Codeblock hat, normalerweise gegen Ende, mit
if __name__ == '__main__':
.-m
ohne das aktuelle Verzeichnis zum Pfad hinzuzufügen:Ein Kommentar hier an anderer Stelle sagt:
Nun, dies zeigt das mögliche Problem - (in Windows entfernen Sie die Anführungszeichen):
Verwenden Sie das
-I
Flag, um dies für Produktionsumgebungen zu sperren (neu in Version 3.4):aus den Dokumenten :
Was macht
__package__
dasEs ermöglicht explizite relative Importe, die für diese Frage jedoch nicht besonders wichtig sind - siehe diese Antwort hier: Was ist der Zweck des Attributs "__package__" in Python?
quelle
Der Hauptgrund, ein Modul (oder Paket) als Skript mit -m auszuführen, besteht in der Vereinfachung der Bereitstellung, insbesondere unter Windows. Sie können Skripte an derselben Stelle in der Python-Bibliothek installieren, an der sich die Module normalerweise befinden - anstatt PATH oder globale ausführbare Verzeichnisse wie ~ / .local zu verschmutzen (das Skriptverzeichnis pro Benutzer ist in Windows lächerlich schwer zu finden).
Dann geben Sie einfach -m ein und Python findet das Skript automatisch.
python -m pip
Finden Sie beispielsweise den richtigen Pip für dieselbe Instanz des Python-Interpreters, der ihn ausführt. Ohne -m, wenn der Benutzer mehrere Python-Versionen installiert hat, welche wäre die "globale" Pip?Wenn der Benutzer "klassische" Einstiegspunkte für Befehlszeilenskripte bevorzugt, können diese einfach als kleine Skripte irgendwo in PATH hinzugefügt werden, oder pip kann diese bei der Installation mit dem Parameter entry_points in setup.py erstellen.
Suchen Sie einfach nach
__name__ == '__main__'
anderen nicht zuverlässigen Implementierungsdetails und ignorieren Sie diese.quelle