Яке призначення перемикача -m?


174

Чи можете ви пояснити мені, в чому різниця між дзвінками?

python -m mymod1 mymod2.py args

і

python mymod1.py mymod2.py args

Здається, в обох випадках mymod1.pyназивається і sys.argvє

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

Отже, для чого -mпотрібен вимикач?


Будь ласка, виправте мене, якщо я помиляюся, але, -mздається, шукає mymod1шлях до бібліотеки за замовчуванням. Приклад: python -m SimpleHTTPServerпрацює, тоді як python SimpleHTTPServerне вдається can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory.
Бась

7
Я на насправді знайшов відповідь тут ясний: stackoverflow.com/questions/46319694 / ...
Casebash

Відповіді:


137

Перший рядок Rationaleрозділу PEP 338 говорить:

Python 2.4 додає перемикач командного рядка -m, щоб дозволити розташування модулів, використовуючи простір імен модуля Python для виконання як сценарії. Мотиваційними прикладами були стандартні бібліотечні модулі, такі як pdb та профіль, і реалізація Python 2.4 чудово підходить для цієї обмеженої мети.

Таким чином, ви можете вказати будь-який модуль у шляху пошуку Python таким чином, а не лише файли в поточному каталозі. Ви правильні, що python mymod1.py mymod2.py argsмає такий же ефект. У першому рядку Scope of this proposalрозділу зазначено:

У Python 2.4 модуль, розташований за допомогою -m, виконується так само, як якщо б його ім'я файлу було вказано в командному рядку.

З -mбільш можливо, як працювати з модулями , які є частиною пакету, і т.д. Це те, що інша частина PEP 338 об. Прочитайте його для отримання додаткової інформації.


47
Моє улюблене використання - -mце python -m SimpleHTTPServer. Дуже зручно, коли мені потрібно поділитися деякими файлами, не використовуючи флешку USB.
arifwn

21
@arifwn Запуск Python3 вимагає невеликого оновлення, python -m http.serverі це все ще приголомшливо!
Kit Roed

12
TL; DR: 1) Ви можете запустити, python -m package.subpackage.moduleі буде використана нормальна технологія вирішення, не потрібно вказувати точний .pyфайл. 2) Можна відносний імпорт із запущеного модуля без будь-яких обхідних шляхів, оскільки його пакет буде завантажений по дорозі. 3) Абсолютний імпорт буде базуватися на вашому поточному каталозі, а не на директорії, де знаходиться .pyфайл ( ''знаходиться на чолі sys.path, а не /path/to/my, якщо сценарій знаходиться у /path/to/my/script.py).
clacke

З цієї відповіді не з’ясовується, що це працює лише на підмножині модулів, які виконуються, тобто мають __main__.pyфайл. Більшість не робить і зламається, наприклад, python -m sys 'print(sys.version)'не вдається python: No code object available for sys. Запропонуйте вам це зрозуміти у відповіді.
smci

19

Варто згадати, що це працює лише в тому__main__.py випадку, якщо в пакеті є файл. В іншому випадку цей пакет неможливо виконати безпосередньо.

python -m some_package some_arguments

Інтерпретатор python шукатиме __main__.pyфайл у шляху пакета для виконання. Це еквівалентно:

python path_to_package/__main__.py somearguments

Він виконає вміст після:

if __name__ == "__main__":

2
Що з файлом init пакета? За наявності головного файлу буде також викликано init?
змінна

@variable Так, init .py буде викликано до виклику main .py
Марк Рукер

1

Незважаючи на запитання та відповіді на це кілька разів (наприклад, тут , тут , тут , і тут ), на мою думку, жодна з існуючих відповідей повністю чи стисло не відображає всіх наслідків -mпрапора. Тому далі буде намагатися покращити те, що було раніше.

Вступ (TLDR)

-mКоманда робить багато речей , не всі з них обов'язково будуть потрібні весь час. Коротше кажучи: (1) дозволяє пітон, щоб скрипти виконувалися з допомогою MODULENAME , а не ім'я файлу (2) дозволяє вибрати каталог , щоб додати до sys.pathдля importдозволу і (3) дозволяє пітон сценарії з відносно імпорту повинні бути виконані з командного рядка .

Прелімінарії

Щоб пояснити -mпрапор, спершу треба чітко визначити термінологію.

По-перше, первинний організаційний підрозділ Python відомий як модуль . Модуль поставляється в одному з двох варіантів: кодові модулі та модулі пакетів. Модуль коду - це будь-який файл, який містить виконуваний код python. Пакетний модуль - це каталог, який містить інші модулі (або модулі коду, або пакети). Найпоширенішим типом модулів коду є *.pyфайли, тоді як найпоширеніший тип модулів пакету - це каталоги, що містять __init__.pyфайл.

По-друге, всі модулі можна однозначно ідентифікувати двома різними способами: <modulename>та <filename>. Модулі найчастіше ідентифікуються за іменем модуля в коді Python (наприклад, import <modulename>) та за назвою файлу в командному рядку (наприклад, python <filename>). Усі інтерпретатори Python можуть перетворювати модулемени у назви файлів через набір чітко визначених правил. Ці правила залежать від sys.pathзмінної, і тому відображення можна змінити, змінивши це значення (докладніше про те, як це робиться, див. PEP 302 ).

По-третє, всі модулі (і код, і пакет) можуть бути виконані (під яким ми маємо на увазі код, пов'язаний з модулем, буде оцінено інтерпретатором Python). Залежно від способу виконання та типу модуля, який код оцінюється та коли, може змінитися зовсім небагато. Наприклад, якщо хтось виконує пакетний модуль до python <filename>цього часу, <filename>/__init__.pyвін буде оцінюватися з подальшим виконанням <filename>/__main__.py. З іншого боку, якщо хтось виконує той самий модуль пакету, import <modulename>тоді виконуватимуться лише пакети __init__.py.

Історичний розвиток Росії -m

Прапор -m вперше було введено в Python 2.4.1 . Спочатку його єдиною метою було створення альтернативного способу ідентифікації модуля python для виконання. Тобто, якщо ми знали <filename>і <modulename>модуль, і модуль, наступні дві команди були еквівалентними: python <filename> <args>і python -m <modulename> <args>. Крім того, згідно з PEP 338, ця ітерація -mпрацювала лише з модуленами верхнього рівня (тобто модулями, які можна було знайти безпосередньо на sys.path без будь-яких пакетів, що втручалися).

Із завершенням PEP 338-m функціональність була розширена для підтримки <modulename>уявлень за межами верхніх modulenames рівня. Це означало імена, http.serverякі зараз повністю підтримуються. Це вдосконалення також означало, що зараз завантажуються всі пакунки в модулі (тобто всі __init__.pyфайли пакетів оцінювалися) разом із самим модулем.

Кінцеве значне підвищення функції для -mприйшло з PEP 366 . За допомогою цього оновлення -mнабула можливість підтримувати не лише абсолютний імпорт, але й явний відносний імпорт. Це було досягнуто шляхом зміни __package__змінної для названого модуля в -mкоманді.

Використовуйте випадки

Є два помітні випадки використання прапора -m:

  1. Виконати модулі з командного рядка, для якого можна не знати їх імені файлів. Цей випадок використання використовує той факт, що інтерпретатор Python знає, як перетворити модулемени у назви файлів. Це особливо вигідно, коли потрібно запускати stdlib модулі або сторонні модулі з командного рядка. Наприклад, дуже мало людей знають ім'я файлу для http.serverмодуля, але більшість людей знають його ім'я, тому ми можемо виконати його з командного рядка за допомогою python -m http.server.

  2. Виконати локальний пакет, що містить абсолютний імпорт без необхідності його встановлення. Цей випадок використання детально описаний у PEP 338 і використовує той факт, що поточний робочий каталог додається до sys.pathкаталогу модуля. Цей випадок використання дуже схожий на pip install -e .встановлення пакета в режимі розробки / редагування.

Недоліки

З урахуванням усіх удосконалень -mпротягом багатьох років у нього все ще є один головний недолік - він може виконувати лише кодові модулі, написані в python (тобто * .py). Наприклад, якщо -mвикористовується для виконання модуля коду, зібраного на C, буде створено наступну помилку No code object available for <modulename>(див. Тут для більш детальної інформації).

Детальні порівняння

Ефекти виконання модуля за допомогою команди python (тобто, python <filename>):

  • sys.path модифікується, щоб включати остаточний каталог у <filename>
  • __name__ встановлено на '__main__'
  • __package__ встановлено на None
  • __init__.py не оцінюється для жодного пакету (включаючи його власний для модулів пакету)
  • __main__.pyоцінюється для пакетних модулів; код оцінюється для модулів коду.

Ефекти виконання модуля через оператор імпорту (тобто import <modulename>):

  • sys.pathце НЕ змінені будь - яким чином
  • __name__ встановлюється в абсолютній формі <modulename>
  • __package__ встановлено для безпосереднього батьківського пакета в <modulename>
  • __init__.py оцінюється для всіх пакетів (включаючи власні для пакетних модулів)
  • __main__.pyце НЕ оцінюється для модулів пакетів; код оцінюється для модулів коду

Ефекти виконання модуля через прапор -m (тобто python -m <modulename>):

  • sys.path модифікується для включення поточного каталогу
  • __name__ встановлено на '__main__'
  • __package__ встановлено для безпосереднього батьківського пакета в <modulename>
  • __init__.py оцінюється для всіх пакетів (включаючи власні для пакетних модулів)
  • __main__.pyоцінюється для пакетних модулів; код оцінюється для модулів коду

Висновок

-mПрапор, в найпростішому, засіб для виконання пітона сценаріїв з командного рядка за допомогою modulenames , а не імена файлів. Крім того, -mнадається додаткова функціональність, яка поєднує в собі потужність importоператорів (наприклад, підтримка явного відносного імпорту та автоматична __init__оцінка пакету ) із зручністю командного рядка python.


Чи можете ви також додати використання пакету для виклику, використовуючи python -m packagenameвказане тут: stackoverflow.com/a/53772635/1779091
змінна

@варіабельна хороша ідея, я додав розділ "Використовувати випадок", який включає це.
Марк Рукер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.