Pomimo tego, że zadawano to pytanie i odpowiadano na nie kilka razy (np. Tutaj , tutaj , tutaj i tutaj ), moim zdaniem żadna istniejąca odpowiedź nie oddaje w pełni ani zwięźle wszystkich implikacji -m
flagi. Dlatego poniższe postarają się ulepszyć to, co było wcześniej.
Wprowadzenie (TLDR)
-m
Komenda robi wiele rzeczy, nie wszystkie z nich muszą być potrzebne przez cały czas. W skrócie: (1) pozwala na wykonywanie skryptów Pythona za pomocą nazwy modułu zamiast nazwy pliku (2) pozwala wybrać katalog do dodania w sys.path
celu import
rozwiązania problemu oraz (3) umożliwia wykonywanie skryptów Pythona z relatywnymi importami z wiersza poleceń .
Czynności wstępne
Aby wyjaśnić -m
flagę, musimy najpierw wyjaśnić trochę terminologii.
Po pierwsze, podstawowa jednostka organizacyjna Pythona jest nazywana modułem . Moduły występują w jednym z dwóch rodzajów: moduły kodu i moduły pakietów. Moduł kodu to dowolny plik zawierający kod wykonywalny w języku Python. Moduł pakietu to katalog zawierający inne moduły (moduły kodu lub moduły pakietów). Najpopularniejszym typem modułów kodu są *.py
pliki, podczas gdy najpopularniejszym typem modułów pakietu są katalogi zawierające __init__.py
plik.
Po drugie, wszystkie moduły można jednoznacznie zidentyfikować na dwa różne sposoby: <modulename>
i <filename>
. Moduły są najczęściej identyfikowane przez nazwę modułu w kodzie Pythona (np. import <modulename>
) I nazwę pliku w wierszu poleceń (np python <filename>
.). Wszystkie interpretery Pythona mogą konwertować nazwy modulów na nazwy plików za pomocą zestawu dobrze zdefiniowanych reguł. Reguły te zależą od sys.path
zmiennej i dlatego mapowanie można zmienić, zmieniając tę wartość (więcej informacji na temat tego, jak to się robi, znajduje się w PEP 302 ).
Po trzecie, wszystkie moduły (zarówno kod, jak i pakiet) mogą zostać wykonane (przez co rozumiemy kod powiązany z modułem zostanie oceniony przez interpreter Pythona). W zależności od metody wykonania i typu modułu, jaki kod jest oceniany i kiedy, może się nieco zmienić. Na przykład, jeśli wykonuje się moduł pakietu za pośrednictwem, python <filename>
to <filename>/__init__.py
zostanie ocenione, a po nim <filename>/__main__.py
. Z drugiej strony, jeśli ktoś wykonuje ten sam moduł pakietu za pośrednictwem, import <modulename>
to tylko pakiety __init__.py
zostaną wykonane.
Rozwój historyczny -m
Flaga -m została po raz pierwszy wprowadzona w Pythonie 2.4.1 . Początkowo jego jedynym celem było zapewnienie alternatywnych sposobów identyfikacji modułu Pythona do wykonania. Oznacza to, że gdybyśmy znali zarówno moduł, jak <filename>
i <modulename>
dla modułu, następujące dwa polecenia byłyby równoważne: python <filename> <args>
i python -m <modulename> <args>
. Ponadto, zgodnie z PEP 338, ta iteracja -m
działała tylko z nazwami modulów najwyższego poziomu (tj. Modułami, które można znaleźć bezpośrednio w sys.path bez żadnych pakietów pośredniczących).
Wraz z zakończeniem PEP 338-m
funkcjonalność została rozszerzona na wsparcie <modulename>
reprezentacji poza najlepszych moduleNames szczebla. Oznaczało to, że nazwy takie jak http.server
były teraz w pełni obsługiwane. To ulepszenie oznaczało również, że wszystkie pakiety w module zostały załadowane (tj. Wszystkie __init__.py
pliki pakietów zostały ocenione) wraz z samym modułem.
Ostatnie główne ulepszenie funkcji -m
przyszło wraz z PEP 366 . Dzięki tej aktualizacji -m
zyskał możliwość obsługi nie tylko importu bezwzględnego, ale także jawnego importu względnego. Osiągnięto to poprzez zmodyfikowanie __package__
zmiennej dla nazwanego modułu w -m
poleceniu.
Przypadków użycia
Istnieją dwa godne uwagi przypadki użycia flagi -m:
Aby uruchomić moduły z wiersza poleceń, dla których można nie znać ich nazw plików. Ten przypadek użycia wykorzystuje fakt, że interpreter Pythona wie, jak przekonwertować nazwy modulów na nazwy plików. Jest to szczególnie korzystne, gdy chce się uruchomić moduły stdlib lub moduł innej firmy z wiersza poleceń. Na przykład, bardzo niewiele osób zna nazwę pliku http.server
modułu, ale większość ludzi zna jego nazwę modułu, więc możemy go uruchomić z wiersza poleceń za pomocą python -m http.server
.
Aby wykonać lokalny pakiet zawierający bezwzględne importy bez konieczności instalowania go. Ten przypadek użycia jest szczegółowo opisany w PEP 338 i wykorzystuje fakt, że bieżący katalog roboczy jest dodawany do sys.path
katalogu modułu, a nie do niego. Ten przypadek użycia jest bardzo podobny do używania pip install -e .
do instalowania pakietu w trybie tworzenia / edycji.
Niedociągnięcia
Pomimo wszystkich ulepszeń wprowadzonych na -m
przestrzeni lat, nadal ma jedną poważną wadę - może wykonywać tylko moduły kodu napisane w Pythonie (tj. * .Py). Na przykład, jeśli -m
jest używany do wykonania skompilowanego modułu kodu w C, zostanie wygenerowany następujący błąd No code object available for <modulename>
(zobacz tutaj, aby uzyskać więcej informacji).
Szczegółowe porównania
Efekty wykonania modułu za pomocą polecenia Pythona (tj. python <filename>
):
sys.path
jest modyfikowany, aby uwzględnić ostateczny katalog w <filename>
__name__
jest ustawione na '__main__'
__package__
jest ustawione na None
__init__.py
nie jest oceniany dla żadnego pakietu (w tym własnego dla modułów pakietu)
__main__.py
jest oceniany dla modułów pakietu; kod jest oceniany pod kątem modułów kodu.
Efekty wykonania modułu poprzez instrukcję importu (tj. import <modulename>
):
sys.path
nie jest w żaden sposób modyfikowany
__name__
jest ustawiona na absolutną formę <modulename>
__package__
jest ustawiony na bezpośredni pakiet nadrzędny w <modulename>
__init__.py
jest oceniany dla wszystkich pakietów (w tym własnego dla modułów pakietów)
__main__.py
nie jest oceniany dla modułów pakietu; kod jest oceniany pod kątem modułów kodu
Efekty wykonania modułu za pomocą flagi -m (tj. python -m <modulename>
):
sys.path
jest modyfikowany w celu uwzględnienia bieżącego katalogu
__name__
jest ustawione na '__main__'
__package__
jest ustawiony na bezpośredni pakiet nadrzędny w <modulename>
__init__.py
jest oceniany dla wszystkich pakietów (w tym własnego dla modułów pakietów)
__main__.py
jest oceniany dla modułów pakietu; kod jest oceniany pod kątem modułów kodu
Wniosek
-m
Flaga jest w swej najprostszej, środki do wykonywania skryptów Pythona z linii poleceń za pomocą moduleNames zamiast nazw plików. Dodatkowo -m
zapewnia dodatkową funkcjonalność, która łączy moc import
instrukcji (np. Obsługę jawnych importów względnych i automatycznej __init__
oceny pakietów ) z wygodą wiersza poleceń Pythona.
-m
wydaje się, że wyszukujęmymod1
w domyślnej ścieżce biblioteki. Przykład:python -m SimpleHTTPServer
działa, alepython SimpleHTTPServer
kończy się niepowodzeniem zcan't open file 'SimpleHTTPServer': [Errno 2] No such file or directory
.