-m スイッチの目的は何ですか? 質問する

-m スイッチの目的は何ですか? 質問する

電話との違いを教えてください。

python -m mymod1 mymod2.py args

そして

python mymod1.py mymod2.py args

どちらの場合も、mymod1.pyと呼ばれsys.argv

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

それで、-mスイッチは何のためにあるのでしょうか?

ベストアンサー1

この質問は何度も尋ねられ、答えられてきたにもかかわらず(例:ここここここ、 そしてここ)、私の意見では、既存の回答では旗の意味をすべて完全に、または簡潔に捉えることはできません-m。したがって、以下では、これまでの回答を改善することを試みます。

はじめに(TLDR)

この-mフラグは多くのことを行いますが、常にすべてのことが必要になるわけではありません。簡単に言うと、次の場合に使用できます: (1) ファイル名ではなくモジュール名を使用してコマンドラインから Python コードを実行する (2)解決sys.pathに使用するディレクトリを追加するimport(3) コマンドラインから相対インポートを含む Python コードを実行する。

予選

旗について説明するには、-mまず少し用語を説明する必要があります。

Pythonの主な組織単位はモジュールモジュールには、コード モジュールとパッケージ モジュールの 2 種類があります。コード モジュールは、Python 実行可能コードを含むファイルです。パッケージ モジュールは、他のモジュール (コード モジュールまたはパッケージ モジュール) を含むディレクトリです。最も一般的なタイプのコード モジュールはファイルであり*.py、最も一般的なタイプのパッケージ モジュールは__init__.pyファイルを含むディレクトリです。

Python では、モジュールをモジュール名とファイル名の 2 つの方法で一意に識別できます。一般に、モジュールは Python コード内ではモジュール名 (例import <modulename>) で識別され、コマンドラインではファイル名 (例python <filename>) で識別されます。すべての Python インタプリタは、同じいくつかの明確に定義されたルールに従って、モジュール名をファイル名に変換できます。これらのルールは、変数に依存しますsys.path。この変数を変更することで、Python がモジュール名をファイル名に変換する方法を変更できます (この方法については、を参照してください)。ペップ302)。

すべてのモジュール (コードとパッケージの両方) を実行できます (つまり、モジュールに関連付けられたコードは Python インタープリターによって評価されます)。実行方法 (およびモジュールの種類) に応じて、どのコードがいつ評価されるかは大きく変わります。たとえば、 を介してパッケージ モジュールを実行すると、python <filename><filename>/__main__.py実行されます。一方、 を介して同じパッケージ モジュールを実行するとimport <modulename>、パッケージのみが__init__.py実行されます。

歴史的発展-m

この-m旗が初めて導入されたのはPython 2.4.1当初、その唯一の目的は、コマンドラインから実行するPythonモジュールを識別するための代替手段を提供することでした。つまり、モジュールの<filename><modulename>の両方がわかっている場合、次の2つのコマンドは同等です。python <filename> <args>python -m <modulename> <args>。この反復処理の1つの制約は、ペップ338は、トップレベルのモジュール名 (つまり、パッケージ モジュールを介さず-mに直接見つけることができるモジュール) でのみ機能していました。sys.path

の完成によりペップ338この機能は、トップレベルを超える表現を-mサポートするように拡張されました。つまり、 などの名前が完全にサポートされるようになりました。また、この拡張により、modulename 自体によって参照されるモジュールに加えて、modulename 内の各親パッケージが評価されるようになりました (つまり、すべての親パッケージファイルが評価されました)。<modulename>http.server__init__.py

-mの最後の主要な機能強化はペップ366このアップグレードにより、-mモジュールを実行するときに絶対インポートだけでなく明示的な相対インポートもサポートできるようになりました。これは、指定されたモジュール名の親モジュールに変数-mを設定するように変更することで実現しました__package__(すでに実行されている他のすべての処理に加えて)。

ユースケース

このフラグには注目すべき使用例が 2 つあります-m

  1. ファイル名がわからないモジュールをコマンドラインから実行します。このユースケースでは、Python インタープリターがモジュール名をファイル名に変換する方法を知っているという事実を活用します。これは、コマンドラインから stdlib モジュールまたはサードパーティ モジュールを実行する場合に特に便利です。たとえば、モジュールのファイル名を知っている人はほとんどいませんhttp.serverが、ほとんどの人はモジュール名を知っているので、 . を使用してコマンドラインから実行できますpython -m http.server

  2. 絶対または相対インポートを含むローカルパッケージをインストールせずに実行します。このユースケースの詳細は、ペップ338sys.pathモジュールのディレクトリではなく、現在の作業ディレクトリが追加されるという事実を活用します。この使用例はpip install -e .、開発/編集モードでパッケージをインストールする場合と非常によく似ています。

欠点

-mは長年にわたって改良されてきましたが、それでもまだ大きな欠点が 1 つあります。Python で書かれたモジュール (つまり*.py) しか実行できないのです。たとえば、-mを C でコンパイルされたコード モジュールの実行に使用すると、次のエラーが発生しますNo code object available for <modulename>(ここ詳細については)。

詳細な比較

インポート ステートメントによるモジュール実行 (つまり、import <modulename>):

  • sys.pathいかなる形でも変更されていない
  • __name__絶対形式に設定されます<modulename>
  • __package__直近の親パッケージに設定されます<modulename>
  • __init__.pyすべてのパッケージに対して評価されます(パッケージモジュールの場合は自身のパッケージも含む)
  • __main__.pyパッケージモジュールでは評価されませ。コードはコードモジュールで評価されます。

ファイル名を指定したコマンドライン経由のモジュール実行 (つまり、python <filename>):

  • sys.path最終ディレクトリを含めるように変更されます<filename>
  • __name__に設定されています'__main__'
  • __package__に設定されていますNone
  • __init__.pyどのパッケージに対しても評価されない(パッケージモジュールの自身のパッケージを含む)
  • __main__.pyパッケージ モジュールの場合は評価され、コード モジュールの場合はコードが評価されます。

モジュール名 (つまり、 ) を使用したコマンドライン経由のモジュール実行python -m <modulename>:

  • sys.path現在のディレクトリを含むように変更されます
  • __name__に設定されています'__main__'
  • __package__直近の親パッケージに設定されます<modulename>
  • __init__.pyすべてのパッケージに対して評価されます(パッケージモジュールの場合は自身のパッケージも含む)
  • __main__.pyパッケージモジュールに対して評価され、コードはコードモジュールに対して評価される

結論

フラグ-mは、簡単に言えば、ファイル名ではなくモジュール名を使用してコマンドラインから Python スクリプトを実行する手段です。ただし、の真の力は、ステートメントの力 (明示的な相対インポートのサポートや自動パッケージ評価など) とコマンドラインの利便性-mを組み合わせる能力にあります。import__init__

おすすめ記事