Quando você usa o -m
sinalizador de linha de comando , o Python importa um módulo ou pacote para você e o executa como um script. Quando você não usa o -m
sinalizador, o arquivo nomeado é executado apenas como um script .
A distinção é importante quando você tenta executar um pacote. Existe uma grande diferença entre:
python foo/bar/baz.py
e
python -m foo.bar.baz
como no último caso, foo.bar
é importado e as importações relativas funcionarão corretamente foo.bar
como ponto de partida.
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__
Como resultado, o Python precisa realmente se preocupar com os pacotes ao usar a -m
opção. Um script normal nunca pode ser um pacote, portanto, __package__
é definido como None
.
Mas execute um pacote ou módulo dentro de um pacote com -m
e agora há pelo menos a possibilidade de um pacote, então a __package__
variável é definida como um valor de string; na demonstração acima, ele é definido como foo.bar
, para módulos simples que não estão dentro de um pacote, é definido como uma string vazia.
Quanto ao __main__
módulo ; Python importa scripts que estão sendo executados como se fossem um módulo normal. Um novo objeto de módulo é criado para conter o namespace global, armazenado em sys.modules['__main__']
. É a isso que a __name__
variável se refere, é a chave dessa estrutura.
Para pacotes, você pode criar um __main__.py
módulo e executá-lo durante a execução python -m package_name
; na verdade, essa é a única maneira que você pode executar um pacote como um script:
$ 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__
Portanto, ao nomear um pacote para execução -m
, o Python procura um __main__
módulo contido nesse pacote e o executa como um script. Seu nome ainda é definido como __main__
e o objeto de módulo ainda está armazenado em sys.modules['__main__']
.
PYTHONPATH=test python -m foo.bar
? Você poderia explicar em detalhes, por favor?PYTHONPATH
define uma variável de ambiente; ele expande a série de diretórios onde o Python irá procurar por módulos ao importar; aqui ele adiciona otest
diretório a essa série. Ao colocá-lo na mesma linha de comando, ele se aplica apenas a esse únicopython
comando.-m
diz ao Python para importar um módulo específico, como se você o tivesse executadoimport foo.bar
. No entanto, Python executará automaticamente um__main__
módulo dentro de um pacote como um script quando você usar essa opção.having to use -m always is not that user-.friendly.
Acho que misturar usando e não usando-m
é menos amigável.-m
só funciona para o diretório atual ou diretórios já registrados no caminho de pesquisa. Esse foi o meu ponto.-m
não é algo que você dá aos usuários finais exatamente por causa desse problema de usabilidade.from Photos import ...
vou reclamar. Então seriaimport Photos.<something>
.import Photos
só funciona porque o Python suporta pacotes com namespaces (onde duas distribuições separadas fornecemPhotos.foo
ePhotos.bar
separadamente e podem ser gerenciados de forma independente).Execução de código Python com opção -m ou não
Use a
-m
bandeira.Os resultados são praticamente os mesmos quando você tem um script, mas quando você desenvolve um pacote, sem o
-m
sinalizador, não há como fazer as importações funcionarem corretamente se você deseja executar um subpacote ou módulo no pacote como a entrada principal aponte para o seu programa (e acredite, eu tentei.)Os docs
Como os documentos na sinalização -m dizem:
e
tão
é aproximadamente equivalente a
(presumindo que você não tenha um pacote ou script em seu diretório atual chamado pdb.py)
Explicação:
O comportamento é tornado "deliberadamente semelhante a" scripts.
Algum código Python deve ser executado como um módulo: (acho que este exemplo é melhor do que o exemplo de documento de opção de linha de comando)
E a partir dos destaques da nota de lançamento para Python 2.4 :
Questão a seguir
Isso significa que qualquer módulo que você pode consultar com uma instrução de importação pode ser executado como o ponto de entrada do programa - se ele tiver um bloco de código, geralmente próximo ao final, com
if __name__ == '__main__':
.-m
sem adicionar o diretório atual ao caminho:Um comentário aqui em outro lugar diz:
Bem, isso demonstra o possível problema - (no Windows, remova as aspas):
Use a
-I
sinalização para bloquear isso para ambientes de produção (novo na versão 3.4):dos documentos :
O que
__package__
fazer?Ele permite importações relativas explícitas, embora não particularmente pertinentes a essa pergunta - veja esta resposta aqui: Qual é o propósito do atributo "__package__" em Python?
fonte
O principal motivo para executar um módulo (ou pacote) como um script com -m é para simplificar a implantação, especialmente no Windows. Você pode instalar scripts no mesmo local na biblioteca Python onde os módulos normalmente vão - em vez de poluir o PATH ou diretórios executáveis globais como ~ / .local (o diretório de scripts por usuário é ridiculamente difícil de encontrar no Windows).
Então você apenas digita -m e o Python encontra o script automaticamente. Por exemplo,
python -m pip
encontrará o pip correto para a mesma instância do interpretador Python que o executa. Sem -m, se o usuário tiver várias versões do Python instaladas, qual seria o pip "global"?Se o usuário preferir pontos de entrada "clássicos" para scripts de linha de comando, eles podem ser facilmente adicionados como pequenos scripts em algum lugar no PATH, ou pip pode criá-los no momento da instalação com o parâmetro entry_points em setup.py.
Portanto, apenas verifique
__name__ == '__main__'
e ignore outros detalhes de implementação não confiáveis.fonte