Apesar de esta pergunta ter sido feita e respondida várias vezes (por exemplo, aqui , aqui , aqui e aqui ), na minha opinião, nenhuma resposta existente captura total ou concisamente todas as implicações da -m
bandeira. Portanto, o seguinte tentará melhorar o que veio antes.
Introdução (TLDR)
O -m
comando faz muitas coisas, nem todas serão necessariamente necessárias o tempo todo. Em suma,: (1) permite scripts python para ser executado via modulename em vez de nome de arquivo (2) permite escolher um diretório para adicionar ao sys.path
de import
resolução e (3) permite que os scripts python com importações em relação a ser executado a partir da linha de comando .
Preliminares
Para explicar a -m
bandeira, primeiro precisamos esclarecer um pouco a terminologia.
Primeiro, a principal unidade organizacional do Python é conhecida como módulo . Os módulos vêm em um de dois tipos: módulos de código e módulos de pacote. Um módulo de código é qualquer arquivo que contém código executável python. Um módulo de pacote é um diretório que contém outros módulos (módulos de código ou módulos de pacote). O tipo mais comum de módulos de código são os *.py
arquivos, enquanto o tipo mais comum de módulos de pacote são os diretórios que contêm um __init__.py
arquivo.
Segundo, todos os módulos podem ser identificados exclusivamente de duas maneiras distintas: <modulename>
e <filename>
. Os módulos geralmente são identificados pelo nome do módulo no código Python (por exemplo, import <modulename>
) e pelo nome do arquivo na linha de comando (por exemplo,python <filename>
). Todos os intérpretes Python podem converter nomes de módulos em nomes de arquivos por meio de um conjunto de regras bem definidas. Essas regras dependem da sys.path
variável e, portanto, o mapeamento pode ser alterado alterando esse valor (para mais informações sobre como isso é feito, consulte PEP 302 ).
Terceiro, todos os módulos (código e pacote) podem ser executados (com o que queremos dizer que o código associado ao módulo será avaliado pelo intérprete Python). Dependendo do método de execução e do tipo de módulo, qual código é avaliado e quando pode mudar um pouco. Por exemplo, se alguém executar um módulo de pacote via, python <filename>
então <filename>/__init__.py
será avaliado seguido por <filename>/__main__.py
. Por outro lado, se alguém executar o mesmo módulo de pacote via import <modulename>
, somente os pacotes __init__.py
serão executados.
Desenvolvimento Histórico de -m
O sinalizador -m foi introduzido pela primeira vez no Python 2.4.1 . Inicialmente, seu único objetivo era fornecer um meio alternativo de identificar um módulo python para executar. Isto é, se soubéssemos tanto do <filename>
e <modulename>
para um módulo, em seguida, os dois comandos a seguir são equivalentes: python <filename> <args>
e python -m <modulename> <args>
. Além disso, de acordo com a PEP 338 essa iteração -m
funcionava apenas com nomes de módulos de nível superior (ou seja, módulos que podiam ser encontrados diretamente no sys.path sem nenhum pacote intermediário).
Com a conclusão do PEP 338, a -m
funcionalidade foi estendida para suportar <modulename>
representações além dos nomes de módulo de nível superior. Isso significava nomes como http.server
agora eram totalmente suportados. Esse aprimoramento também significou que todos os pacotes em um módulo agora estavam carregados (ou seja, todos os pacotes__init__.py
arquivos de foram avaliados), junto com o próprio módulo.
O aprimoramento final dos principais recursos -m
veio com o PEP 366 . Com essa atualização, -m
ganhou a capacidade de suportar não apenas importações absolutas, mas também importações relativas explícitas. Isso foi obtido modificando a __package__
variável do módulo nomeado no diretório-m
comando.
Casos de Uso
Existem dois casos de uso notáveis para o sinalizador -m:
Para executar módulos a partir da linha de comando para os quais um pode não saber seu nome de arquivo. Esse caso de uso aproveita o fato de que o intérprete Python sabe como converter nomes de módulos em nomes de arquivos. Isso é particularmente vantajoso quando se deseja executar módulos stdlib ou módulo de terceiros a partir da linha de comando. Por exemplo, poucas pessoas sabem o nome do arquivo para o http.server
módulo, mas a maioria conhece o nome do módulo para que possamos executá-lo na linha de comando usando python -m http.server
.
Para executar um pacote local contendo importações absolutas sem a necessidade de instalá-lo. Este caso de uso é detalhado no PEP 338 e aproveita o fato de o diretório de trabalho atual ser adicionado ao sys.path
invés do diretório do módulo. Esse caso de uso é muito semelhante ao uso pip install -e .
para instalar um pacote no modo de desenvolvimento / edição.
Deficiências
Com todos os aprimoramentos feitos ao -m
longo dos anos, ele ainda possui uma grande falha - ele pode executar apenas módulos de código escritos em python (ou seja, * .py). Por exemplo, se -m
for usado para executar um módulo de código compilado em C, o seguinte erro será produzido No code object available for <modulename>
(veja aqui para mais detalhes).
Comparações detalhadas
Efeitos da execução do módulo via comando python (ie, python <filename>
):
sys.path
é modificado para incluir o diretório final em <filename>
__name__
está configurado para '__main__'
__package__
está configurado para None
__init__.py
não é avaliado para nenhum pacote (incluindo o próprio para módulos de pacote)
__main__.py
é avaliado para módulos de pacotes; o código é avaliado para módulos de código.
Efeitos da execução do módulo via declaração de importação (ou seja import <modulename>
):
sys.path
não é modificado de forma alguma
__name__
está definido para a forma absoluta de <modulename>
__package__
está definido como o pacote pai imediato em <modulename>
__init__.py
é avaliado para todos os pacotes (incluindo os próprios para módulos de pacotes)
__main__.py
não é avaliado para módulos de pacote; o código é avaliado para módulos de código
Efeitos da execução do módulo via sinalizador -m (ou seja python -m <modulename>
):
sys.path
é modificado para incluir o diretório atual
__name__
está configurado para '__main__'
__package__
está definido como o pacote pai imediato em <modulename>
__init__.py
é avaliado para todos os pacotes (incluindo os próprios para módulos de pacotes)
__main__.py
é avaliado para módulos de pacotes; o código é avaliado para módulos de código
Conclusão
O -m
sinalizador é, na sua forma mais simples, um meio de executar scripts python a partir da linha de comando usando nomes de módulos em vez de nomes de arquivos. Além disso, -m
fornece funcionalidade adicional que combina o poder das import
instruções (por exemplo, suporte a importações relativas explícitas e __init__
avaliação automática de pacotes ) com a conveniência da linha de comando python.
-m
parece procurarmymod1
no caminho da biblioteca padrão. Exemplo:python -m SimpleHTTPServer
funciona, enquantopython SimpleHTTPServer
falha comcan't open file 'SimpleHTTPServer': [Errno 2] No such file or directory
.