Когда вы используете -m
флаг командной строки , Python импортирует для вас модуль или пакет , а затем запускает его как сценарий. Когда вы не используете -m
флаг, названный вами файл запускается как скрипт .
Это различие важно, когда вы пытаетесь запустить пакет. Есть большая разница между:
python foo/bar/baz.py
и
python -m foo.bar.baz
как и в последнем случае, foo.bar
импортируется, и относительный импорт будет правильно работать с foo.bar
отправной точкой.
Демо:
$ 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__
В результате Python должен действительно заботиться о пакетах при использовании -m
переключателя. Обычный скрипт никогда не может быть пакетом, поэтому для __package__
него установлено значение None
.
Но запустите пакет или модуль внутри пакета с помощью, -m
и теперь есть, по крайней мере, возможность пакета, поэтому для __package__
переменной установлено строковое значение; в приведенной выше демонстрации он foo.bar
установлен в пустую строку для простых модулей, не находящихся внутри пакета.
Что касается __main__
модуля ; Python импортирует выполняемые скрипты, как обычный модуль. Создается новый объект модуля для хранения глобального пространства имен, хранящегося в sys.modules['__main__']
. Это то, к чему __name__
относится переменная, это ключ в этой структуре.
Для пакетов вы можете создать __main__.py
модуль и запустить его при запуске python -m package_name
; в том , что это единственный способ , которым Вы можете запустить пакет как сценарий:
$ 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__
Итак, при присвоении имени пакету для работы -m
Python ищет __main__
модуль, содержащийся в этом пакете, и выполняет его как скрипт. Тогда его имя все еще будет установлено __main__
, и объект модуля все еще будет сохранен в sys.modules['__main__']
.
PYTHONPATH=test python -m foo.bar
? Не могли бы вы объяснить это подробнее?PYTHONPATH
устанавливает переменную окружения; расширяет серию каталогов, в которых Python будет искать модули при импорте; здесь он добавляетtest
каталог к этой серии. Помещая его в ту же командную строку, он применяется только к этой единственнойpython
команде.-m
сообщает Python, что нужно импортировать определенный модуль, как если бы вы его запустилиimport foo.bar
. Однако__main__
при использовании этого переключателя Python автоматически запускает модуль внутри пакета как сценарий.having to use -m always is not that user-.friendly.
Я думаю, что использование и неиспользование смеси-m
менее удобно для пользователя.-m
работает только для текущего каталога или каталогов, уже зарегистрированных в пути поиска. Это была моя точка зрения.-m
это не то, что вы даете конечным пользователям по той самой проблеме удобства использования.from Photos import ...
буду жаловаться. Так быimport Photos.<something>
.import Photos
работает только потому, что Python поддерживает пакеты с пространством имен (где два отдельных дистрибутива предоставляютPhotos.foo
иPhotos.bar
отдельно, и ими можно независимо управлять).Выполнение кода Python с параметром -m или без
Используйте
-m
флаг.Результаты почти такие же, когда у вас есть скрипт, но когда вы разрабатываете пакет без
-m
флага, нет никакого способа заставить импорт работать правильно, если вы хотите запустить подпакет или модуль в пакете в качестве основной записи. укажите на вашу программу (и поверьте, я пробовал.)Документы
Как и в документации по флагу -m :
и
так
примерно эквивалентен
(при условии, что в вашем текущем каталоге нет пакета или скрипта с именем pdb.py)
Пояснение:
Поведение сделано «намеренно подобным» сценариям.
Некоторый код Python предназначен для запуска как модуля: (я думаю, что этот пример лучше, чем пример документа с параметром командной строки)
И из примечаний к выпуску для Python 2.4 :
Дополнительный вопрос
Это означает, что любой модуль, который вы можете найти с помощью оператора импорта, может быть запущен как точка входа в программу - если у него есть блок кода, обычно ближе к концу, с
if __name__ == '__main__':
.-m
без добавления текущего каталога в путь:Комментарий здесь в другом месте гласит:
Что ж, это демонстрирует возможную проблему - (в Windows удалите кавычки):
Используйте
-I
флаг, чтобы заблокировать это для производственных сред (новое в версии 3.4):из документов :
Что
__package__
делать?Это позволяет явный относительный импорт, что не особенно важно для этого вопроса - см. Этот ответ здесь: Какова цель атрибута «__package__» в Python?
источник
Основная причина запускать модуль (или пакет) как сценарий с параметром -m - упростить развертывание, особенно в Windows. Вы можете установить сценарии в то же место в библиотеке Python, где обычно размещаются модули - вместо того, чтобы загрязнять PATH или глобальные каталоги исполняемых файлов, такие как ~ / .local (каталог сценариев для каждого пользователя смехотворно трудно найти в Windows).
Затем вы просто набираете -m, и Python автоматически находит сценарий. Например,
python -m pip
найдет правильный пункт для того же экземпляра интерпретатора Python, который его выполняет. Без -m, если у пользователя установлено несколько версий Python, какая из них будет «глобальной» точкой?Если пользователь предпочитает «классические» точки входа для сценариев командной строки, их можно легко добавить как небольшие сценарии где-нибудь в PATH, или pip может создать их во время установки с параметром entry_points в setup.py.
Поэтому просто проверьте
__name__ == '__main__'
и игнорируйте другие ненадежные детали реализации.источник