電話との違いを教えてください。
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
。
ファイル名がわからないモジュールをコマンドラインから実行します。このユースケースでは、Python インタープリターがモジュール名をファイル名に変換する方法を知っているという事実を活用します。これは、コマンドラインから stdlib モジュールまたはサードパーティ モジュールを実行する場合に特に便利です。たとえば、モジュールのファイル名を知っている人はほとんどいません
http.server
が、ほとんどの人はモジュール名を知っているので、 . を使用してコマンドラインから実行できますpython -m http.server
。絶対または相対インポートを含むローカルパッケージをインストールせずに実行します。このユースケースの詳細は、ペップ338
sys.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__