Wykonywanie kodu Pythona z opcją-m lub nie
Interpreter Pythona ma -m
Moduł opcja " uruchamia jako skrypt moduł biblioteki Moduł".
Z tym kodem Pythona a.py:
if __name__ == "__main__":
print __package__
print __name__
Przetestowałem python -m a
Aby uzyskać
"" <-- Empty String
__main__
Natomiast python a.py
zwraca
None <-- None
__main__
Dla mnie te dwa wywołania wydają się być takie same, z wyjątkiem __pakiet__ nie jest żaden, gdy wywołane jest opcją-m.
Co ciekawe, z python -m runpy a
dostaję to samo co python -m a
z modułem Pythona skompilowanym w celu uzyskania.pyc.
Jaka jest (praktyczna) różnica między tymi inwokacjami? Jakieś plusy i minusy między nimi?
David Beazley w Python Essential Reference wyjaśnia to jako " opcja-m uruchamia moduł biblioteki jako skrypt, który wykonuje wewnątrz modułu _ _ main _ _ przed wykonaniem skryptu". Co to znaczy?
3 answers
Kiedy używasz -m
znacznik linii poleceń, Python zaimportuje dla Ciebie Moduł lub pakiet, a następnie uruchamia go jako skrypt. Jeśli nie używasz znacznika -m
, nazwany plik jest uruchamiany jako po prostu skrypt.
Rozróżnienie jest ważne przy próbie uruchomienia pakietu. Istnieje duża różnica między:
python foo/bar/baz.py
I
python -m foo.bar.baz
Tak jak w tym drugim przypadku, foo.bar
jest importowany i import względny będzie działał poprawnie z foo.bar
jako początkiem punkt.
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__
W rezultacie Python musi dbać o Pakiety podczas używania przełącznika -m
. Normalny skrypt nigdy nie może być pakietem, więc __package__
jest ustawione na None
.
Ale uruchom pakiet lub Moduł wewnątrz pakietu z -m
i teraz istnieje co najmniej możliwość pakietu, więc zmienna __package__
jest ustawiona na wartość łańcuchową; w powyższej demonstracji jest ustawiona na 'foo.bar'
, dla zwykłych modułów Nie wewnątrz pakietu jest ustawia pusty ciąg znaków.
Co do __main__
module , Python importuje Skrypty uruchamiane tak, jak importowałby zwykłe Moduły. Nowy obiekt modułu jest tworzony do przechowywania globalnej przestrzeni nazw i jest przechowywany w sys.modules['__main__']
. Do tego odnosi się zmienna __name__
, jest kluczem w tej strukturze.
Dla pakietów, możesz utworzyć __main__.py
Moduł wewnątrz i uruchomić go podczas uruchamiania python -m package_name
; w rzeczywistości jest to jedyny sposób, w jaki możesz uruchomić pakiet jako scenariusz:
$ 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__
Tak więc, nazywając pakiet do pracy z -m
, Python szuka modułu __main__
zawartego w tym pakiecie i wykonuje go jako skrypt. Jego nazwa jest następnie nadal ustawiona na '__main__'
, a obiekt modułu jest nadal przechowywany w sys.modules['__main__']
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-14 09:16:44
Wykonywanie kodu Pythona z opcją-m lub nie
Użyj flagi -m
.
Wyniki są prawie takie same, gdy masz skrypt, ale kiedy tworzysz pakiet, bez flagi -m
, nie ma sposobu, aby import działał poprawnie, jeśli chcesz uruchomić podpakiet lub moduł w pakiecie jako główny punkt wejścia do twojego programu (i uwierz mi, próbowałem.)
Docs
Jak dokumenty na fladze-m mówią:
Szukaj sys.ścieżka do nazwanego modułu i wykonaj jego zawartość jako moduł
__main__
.
I
Tak jak w przypadku opcji-c, bieżący katalog zostanie dodany do początku sys./ align = "left" /
Więc
python -m pdb
Jest mniej więcej równoważne
python /usr/lib/python3.5/pdb.py
(zakładając, że nie masz pakietu lub skryptu w bieżącym katalogu o nazwie pdb.py)
Wyjaśnienie:
Zachowanie jest " celowo podobne do" Skrypty.
Wiele modułów biblioteki standardowej zawiera kod, który jest wywoływany podczas ich wykonywania jako skrypt. Przykładem może być moduł timeit :
Niektóre kody Pythona mają być uruchamiane jako moduł: (myślę, że ten przykład jest lepszy niż opcja wiersza poleceń przykład doc)
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 33.4 usec per loop
$ python -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 25.2 usec per loop
A z informacji o wydaniu dla Pythona 2.4:
Opcja - m linii poleceń-python-m modulename znajdzie moduł w bibliotece standardowej i wywołaj ją. Na przykład,
python -m pdb
jest równoważnepython /usr/lib/python2.4/pdb.py
Pytanie uzupełniające
Python Essential Reference Davida Beazleya wyjaśnia to jako " The
-m opcja uruchamia moduł biblioteki jako skrypt, który wykonuje wewnątrz modułu __main__
przed wykonaniem skryptu głównego".
Oznacza to, że każdy moduł z instrukcją import może być uruchomiony jako punkt wejścia programu-jeśli posiada kod blok, zwykle pod koniec, z if __name__ == '__main__':
.
-m
bez dodawania bieżącego katalogu do ścieżki:
Komentarz Tu gdzie indziej mówi:
Że opcja-m dodaje również bieżący katalog do sys.path, jest oczywiście problemem bezpieczeństwa (patrz: atak preload). To zachowanie jest podobne do porządku wyszukiwania bibliotek w systemie Windows(zanim zostało ostatnio utwardzone). Szkoda, że Python nie podąża za trendem i nie oferuje prostego sposobu wyłączenia dodawania . do sys.ścieżka
Dobrze, to pokazuje możliwy problem - (w systemie Windows usuń cudzysłowy):
echo "import sys; print(sys.version)" > pdb.py
python -m pdb
3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)]
Użyj znacznika -I
, aby zablokować to dla środowisk produkcyjnych (nowość w wersji 3.4):
python -Im pdb
usage: pdb.py [-c command] ... pyfile [arg] ...
etc...
From the docs :
-I
Uruchom Pythona w trybie izolowanym. Oznacza to również-E I-S. w trybie izolowanym sys.ścieżka nie zawiera katalogu skryptu ani katalogu site-packages użytkownika. All PYTHON* zmienne środowiskowe również są ignorowane. Mogą zostać nałożone dalsze ograniczenia, aby uniemożliwić użytkownikowi wstrzyknięcie złośliwego kodu.
Co robi __package__
?
Umożliwia jawne importowanie względne, nie szczególnie germańskie dla tego pytania - zobacz tę odpowiedź tutaj: jaki jest cel atrybutu "__package__ " w Pythonie?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-19 12:33:03
Głównym powodem uruchomienia modułu (lub pakietu) jako skryptu z opcją-m jest uproszczenie wdrażania, szczególnie w systemie Windows. Skrypty można instalować w tym samym miejscu w bibliotece Pythona, gdzie normalnie idą Moduły - zamiast zanieczyszczać ścieżki lub globalne katalogi wykonywalne, takie jak~/.local (katalog skryptów per-user jest śmiesznie trudny do znalezienia w Windows).
Potem wystarczy wpisać -m i Python znajdzie skrypt automagicznie. Na przykład python -m pip
znajdzie poprawny pip dla tego samego instancja interpretera Pythona, 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 preferuje "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 utworzyć je w czasie instalacji z parametrem entry_points w setup.py.
Więc po prostu sprawdź __name__ == '__main__'
i zignoruj inne nie wiarygodne szczegóły implementacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-08 11:06:08