Jaki jest cel przełącznika -m?

174

Czy mógłbyś mi wyjaśnić, jaka jest różnica między dzwonieniem

python -m mymod1 mymod2.py args

i

python mymod1.py mymod2.py args

Wydaje się, że w obu przypadkach mymod1.pynazywa się i sys.argvjest

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

Więc do czego służy -mprzełącznik?

Charles Brunet
źródło
Popraw mnie, jeśli się mylę, ale -mwydaje się, że wyszukuję mymod1w domyślnej ścieżce biblioteki. Przykład: python -m SimpleHTTPServerdziała, ale python SimpleHTTPServerkończy się niepowodzeniem z can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory.
Basj
7
Właściwie znalazłem tutaj jaśniejszą odpowiedź: stackoverflow.com/questions/46319694/…
Casebash,

Odpowiedzi:

137

Pierwsza linia Rationalesekcji PEP 338 mówi:

Python 2.4 dodaje przełącznik -m wiersza poleceń, aby umożliwić lokalizowanie modułów przy użyciu przestrzeni nazw modułu Pythona do wykonywania jako skrypty. Motywującymi przykładami były standardowe moduły biblioteczne, takie jak pdb i profile, a implementacja Pythona 2.4 jest odpowiednia do tego ograniczonego celu.

Możesz więc w ten sposób określić dowolny moduł w ścieżce wyszukiwania Pythona, a nie tylko pliki w bieżącym katalogu. Masz rację, że python mymod1.py mymod2.py argsma dokładnie ten sam efekt. W pierwszym wierszu Scope of this proposalsekcji podano:

W Pythonie 2.4 moduł zlokalizowany za pomocą -m jest wykonywany tak, jakby jego nazwa pliku została podana w linii poleceń.

Z -mbardziej jest to możliwe, jak pracować z modułami, które są częścią pakietu, itp to co reszta PEP 338 chodzi. Przeczytaj to, aby uzyskać więcej informacji.

agf
źródło
47
Moje ulubione użycie -mto python -m SimpleHTTPServer. Naprawdę przydatne, gdy chcę udostępnić niektóre pliki bez użycia dysku flash USB.
arifwn
21
@arifwn Uruchamianie Pythona3 wymaga niewielkiej aktualizacji, ponieważ python -m http.serveri nadal jest super!
Kit Roed
12
TL; DR: 1) Możesz uruchomić python -m package.subpackage.modulei normalna maszyna do rozwiązywania problemów będzie używana, nie musisz wskazywać dokładnego .pypliku. 2) Możliwe jest wykonanie względnego importu z uruchamianego modułu bez żadnych obejść, ponieważ jego pakiet zostanie załadowany po drodze. 3) Absolutne importowanie będzie oparte na bieżącym katalogu, a nie na katalogu, w którym .pyznajduje się plik ( ''jest na początku sys.path, a nie /path/to/my, jeśli skrypt jest w /path/to/my/script.py).
clacke
Ta odpowiedź nie wyjaśnia, że ​​działa to tylko na podzbiorze modułów, które są wykonywalne, tj. Mają __main__.pyplik. Większość nie pęknie i na przykład python -m sys 'print(sys.version)'nie działa z python: No code object available for sys. Zaproponuj, abyś wyjaśnił to w odpowiedzi.
smci
19

Warto wspomnieć, że działa to tylko wtedy, gdy pakiet ma plik.__main__.py W przeciwnym razie ten pakiet nie może zostać wykonany bezpośrednio.

python -m some_package some_arguments

Interpreter Pythona będzie szukał __main__.pypliku w ścieżce pakietu do wykonania. Jest to równoważne z:

python path_to_package/__main__.py somearguments

Treść zostanie wykonana po:

if __name__ == "__main__":
Marquez.Z
źródło
2
A co z plikiem inicjującym pakiet? Czy w obecności głównego pliku zostanie wywołany również init?
zmienna
@variable Tak init .py zostanie wywołany przed wywołaniem głównego .py
Mark Rucker
1

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 -mflagi. Dlatego poniższe postarają się ulepszyć to, co było wcześniej.

Wprowadzenie (TLDR)

-mKomenda 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.pathcelu importrozwiązania problemu oraz (3) umożliwia wykonywanie skryptów Pythona z relatywnymi importami z wiersza poleceń .

Czynności wstępne

Aby wyjaśnić -mflagę, 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ą *.pypliki, podczas gdy najpopularniejszym typem modułów pakietu są katalogi zawierające __init__.pyplik.

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.pathzmiennej 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__.pyzostanie 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__.pyzostaną 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 -mdział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.serverbył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__.pypliki pakietów zostały ocenione) wraz z samym modułem.

Ostatnie główne ulepszenie funkcji -mprzyszło wraz z PEP 366 . Dzięki tej aktualizacji -mzyskał 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 -mpoleceniu.

Przypadków użycia

Istnieją dwa godne uwagi przypadki użycia flagi -m:

  1. 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.servermoduł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.

  2. 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.pathkatalogu 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 -mprzestrzeni lat, nadal ma jedną poważną wadę - może wykonywać tylko moduły kodu napisane w Pythonie (tj. * .Py). Na przykład, jeśli -mjest 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__.pyjest 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.pathnie 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__.pynie 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__.pyjest oceniany dla modułów pakietu; kod jest oceniany pod kątem modułów kodu

Wniosek

-mFlaga jest w swej najprostszej, środki do wykonywania skryptów Pythona z linii poleceń za pomocą moduleNames zamiast nazw plików. Dodatkowo -mzapewnia dodatkową funkcjonalność, która łączy moc importinstrukcji (np. Obsługę jawnych importów względnych i automatycznej __init__oceny pakietów ) z wygodą wiersza poleceń Pythona.

Mark Rucker
źródło
Czy możesz również dodać użycie wywołującego pakietu za pomocą, python -m packagenamejak wspomniano tutaj: stackoverflow.com/a/53772635/1779091
zmienna
@variable dobry pomysł, dodałem sekcję „Przykład użycia”, która to zawiera.
Mark Rucker