Gdy używasz -m
flagi wiersza poleceń , Python zaimportuje moduł lub pakiet , a następnie uruchomi go jako skrypt. Jeśli nie używasz -m
flagi, nazwany plik jest uruchamiany jako zwykły skrypt .
To rozróżnienie jest ważne, gdy próbujesz uruchomić pakiet. Istnieje duża różnica między:
python foo/bar/baz.py
i
python -m foo.bar.baz
tak jak w drugim przypadku, foo.bar
jest importowany, a import względny będzie działał poprawnie z foo.bar
punktem wyjścia.
Próbny:
$ 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__
W rezultacie Python musi faktycznie dbać o pakiety podczas korzystania z -m
przełącznika. Zwykły skrypt nigdy nie może być pakietem, więc __package__
jest ustawiony na None
.
Ale uruchom pakiet lub moduł wewnątrz pakietu z, -m
a teraz istnieje przynajmniej możliwość pakietu, więc __package__
zmienna jest ustawiana na wartość ciągu; w powyższej demonstracji jest ustawiony na foo.bar
, dla zwykłych modułów nie znajdujących się w pakiecie, jest ustawiony na pusty łańcuch.
Jeśli chodzi o __main__
moduł ; Python importuje uruchamiane skrypty tak, jak zwykły moduł. Tworzony jest nowy obiekt modułu do przechowywania globalnej przestrzeni nazw, przechowywanej w sys.modules['__main__']
. Do tego właśnie __name__
odnosi się zmienna, jest to klucz w tej strukturze.
W przypadku pakietów można utworzyć __main__.py
moduł i uruchomić go podczas działania python -m package_name
; w rzeczywistości jest to jedyny sposób, w jaki można uruchomić pakiet jako skrypt:
$ 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__
Dlatego podczas nadawania nazwy pakietowi do uruchomienia -m
, Python szuka __main__
modułu zawartego w tym pakiecie i wykonuje go jako skrypt. Jego nazwa jest wtedy nadal ustawiona na __main__
, a obiekt modułu jest nadal przechowywany w sys.modules['__main__']
.
PYTHONPATH=test python -m foo.bar
? Czy mógłbyś to szczegółowo wyjaśnić?PYTHONPATH
ustawia zmienną środowiskową; rozszerza serię katalogów, w których Python będzie szukał modułów podczas importu; tutaj dodajetest
katalog do tej serii. Umieszczając go w tej samej linii poleceń, ma zastosowanie tylko do tego pojedynczegopython
polecenia.-m
mówi Pythonowi, aby zaimportował określony moduł, tak jakbyś uruchomiłimport foo.bar
. Jednak Python automatycznie uruchomi__main__
moduł w pakiecie jako skrypt, gdy użyjesz tego przełącznika.having to use -m always is not that user-.friendly.
Myślę, że używanie i nie używanie miksu-m
jest mniej przyjazne dla użytkownika.-m
działa tylko dla bieżącego katalogu lub katalogów już zarejestrowanych w ścieżce wyszukiwania. To był mój punkt widzenia.-m
nie jest czymś, co dajesz użytkownikom końcowym w związku z tą samą kwestią użyteczności.from Photos import ...
będzie narzekać. Tak by byłoimport Photos.<something>
.import Photos
działa tylko dlatego, że Python obsługuje pakiety w przestrzeni nazw (gdzie dwie oddzielne dystrybucje zapewniająPhotos.foo
iPhotos.bar
oddzielnie i mogą być niezależnie zarządzane).Wykonanie kodu Pythona z opcją -m lub bez
Użyj
-m
flagi.Wyniki są prawie takie same, gdy masz skrypt, ale kiedy tworzysz pakiet bez
-m
flagi, nie ma sposobu, aby import działał poprawnie, jeśli chcesz uruchomić podpakiet lub moduł w pakiecie jako główny wpis wskaż swój program (i uwierz mi, próbowałem).Dokumenty
Podobnie jak w dokumentach pod flagą -m :
i
więc
jest w przybliżeniu odpowiednikiem
(zakładając, że nie masz pakietu lub skryptu w swoim bieżącym katalogu o nazwie pdb.py)
Wyjaśnienie:
Zachowanie jest „celowo podobne do” skryptów.
Część kodu w Pythonie ma być uruchamiana jako moduł: (myślę, że ten przykład jest lepszy niż przykład w dokumencie z opcją wiersza poleceń)
A z najważniejszych informacji o wydaniu dla Pythona 2.4 :
Pytanie uzupełniające
Oznacza to, że każdy moduł, który można wyszukać za pomocą instrukcji importu, może zostać uruchomiony jako punkt wejścia programu - jeśli ma blok kodu, zwykle pod koniec, z
if __name__ == '__main__':
.-m
bez dodawania bieżącego katalogu do ścieżki:Komentarz tutaj w innym miejscu mówi:
Cóż, to pokazuje możliwy problem - (w Windows usuń cudzysłowy):
Użyj
-I
flagi, aby zablokować to w środowiskach produkcyjnych (nowość w wersji 3.4):z dokumentów :
Co robi
__package__
?Umożliwia to jawne importowanie względne, jednak niezbyt związane z tym pytaniem - zobacz odpowiedź tutaj: Jaki jest cel atrybutu „__package__” w Pythonie?
źródło
Głównym powodem uruchamiania modułu (lub pakietu) jako skryptu z opcją -m jest uproszczenie wdrażania, szczególnie w systemie Windows. Możesz zainstalować skrypty w tym samym miejscu w bibliotece Pythona, w którym zwykle znajdują się moduły - zamiast zanieczyszczać PATH lub globalne katalogi wykonywalne, takie jak ~ / .local (katalog skryptów dla użytkownika jest śmiesznie trudny do znalezienia w systemie Windows).
Następnie po prostu wpisujesz -m, a Python automatycznie odnajduje skrypt. Na przykład
python -m pip
znajdzie poprawny pip dla tej samej instancji interpretera języka Python, który go wykonuje. Bez -m, jeśli użytkownik ma zainstalowanych kilka wersji Pythona, która z nich byłaby „globalnym” pip?Jeśli użytkownik woli „klasyczne” punkty wejścia dla skryptów wiersza poleceń, można je łatwo dodać jako małe skrypty gdzieś w PATH lub pip może je utworzyć w czasie instalacji za pomocą parametru entry_points w pliku setup.py.
Po prostu sprawdź
__name__ == '__main__'
i zignoruj inne niewiarygodne szczegóły implementacji.źródło