pythonインタープリターには-m
moduleオプションがあります。これは「ライブラリモジュールmoduleをスクリプトとして実行します」。
このpythonコードa.pyで:
if __== "__main__":
print __package__
print __name__
python -m a
をテストして取得しました
"" <-- Empty String
__main__
一方、python a.py
は戻ります
None <-- None
__main__
私には、これらの2つの呼び出しは、_mオプションで呼び出されたときに__package__がNoneではないことを除いて同じように見えます。
興味深いことに、python -m runpy a
を使用すると、a.pycを取得するためにコンパイルされたpythonモジュールを使用してpython -m a
と同じ結果が得られます。
これらの呼び出しの(実際の)違いは何ですか?それらの間に長所と短所はありますか?
また、David BeazleyのPython Essential Referenceは、「-mオプションは、メインスクリプトの実行前に__main__モジュール内で実行されるスクリプトとしてライブラリモジュールを実行する」と説明しています。どういう意味ですか?
-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 __== "__main__":
> print __package__
> print __name__
>
> EOF
$ PYTHONPATH=test python test/foo/bar/baz.py
None
__main__
$ PYTHONPATH=test bin/python -m foo.bar.baz
foo.bar
__main__
その結果、Pythonは-m
スイッチを使用するときにパッケージを実際に気にしなければなりません。通常のスクリプトではパッケージをにすることはできません。したがって、__package__
はNone
に設定されます。
しかし、パッケージまたはモジュールinsideを-m
でパッケージを実行すると、少なくとも可能性がありますパッケージの場合、__package__
変数は文字列値に設定されます。上記のデモでは、foo.bar
に設定されています。パッケージ内にないプレーンモジュールの場合、空の文字列に設定されます。
__main__
module; Pythonは、通常のモジュールと同様に実行されているスクリプトをインポートします。 sys.modules['__main__']
に保存されたグローバル名前空間を保持するために、新しいモジュールオブジェクトが作成されます。これは__name__
変数が参照するものであり、その構造のキーです。
パッケージの場合、__main__.py
モジュールを作成し、python -m package_name
の実行時に実行させることができます。実際、これがパッケージをスクリプトとしてcan実行する唯一の方法です:
$ 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__']
に保存されたままです。
-m
フラグを使用します。
スクリプトを使用した場合の結果はほぼ同じですが、パッケージを開発するときに-m
フラグを使用しないと、メインパッケージとしてパッケージ内のサブパッケージまたはモジュールを実行する場合、インポートを正しく動作させる方法がありませんあなたのプログラムへのエントリーポイント(そして信じてください、私は試しました。)
docs のように言う:
Sys.pathで名前付きモジュールを検索し、その内容を
__main__
モジュールとして実行します。
そして
-cオプションと同様に、現在のディレクトリがsys.pathの先頭に追加されます。
そう
python -m pdb
とほぼ同等です
python /usr/lib/python3.5/pdb.py
(pdb.pyという名前の現在のディレクトリにパッケージまたはスクリプトがない場合)
動作は、「意図的にスクリプトに似た」スクリプトになります。
多くの標準ライブラリモジュールには、実行時にスクリプトとして呼び出されるコードが含まれています。例は、 timeitモジュールです:
いくつかのpythonコードは、モジュールとして を実行することを意図しています: (この例は、コマンドラインオプションdocの例よりも優れていると思います)
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 33.4 usec per loop
$ python -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 25.2 usec per loop
そしてリリースノートのPython 2.4 のハイライトから:
-mコマンドラインオプション-python -m modulenameは、標準ライブラリでモジュールを見つけて呼び出します。たとえば、
python -m pdb
はpython /usr/lib/python2.4/pdb.py
と同等です
また、David BeazleyのPython Essential Referenceは、「-mオプションは、ライブラリモジュールを、メインスクリプトの実行前に
__main__
モジュール内で実行するスクリプトとして実行する」と説明しています。
Importステートメントで検索できるモジュールはすべて、プログラムのエントリポイントとして実行できることを意味します。通常、コードブロックがif __== '__main__':
で終了する場合です。
-m
:他の場所のコメントはこう言っています:
-mオプションがsys.pathに現在のディレクトリも追加することは、明らかにセキュリティの問題です(参照:プリロード攻撃)。この動作は、Windowsのライブラリ検索順序(最近強化される前)に似ています。残念ながら、Pythonはトレンドに従っておらず、追加を無効にする簡単な方法を提供していません。 sys.pathへ
さて、これは考えられる問題を示しています-(Windowsでは引用符を削除します):
echo "import sys; print(sys.version)" > pdb.py
python -m pdb
3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)]
-I
フラグを使用して、実稼働環境でこれをロックダウンします(バージョン3.4の新機能)。
python -Im pdb
usage: pdb.py [-c command] ... pyfile [arg] ...
etc...
から ドキュメント :
-I
分離モードでPythonを実行します。これは、-Eおよび-sも意味します。分離モードでは、sys.pathにはスクリプトのディレクトリもユーザーのサイトパッケージディレクトリも含まれません。 PYTHON *環境変数もすべて無視されます。ユーザーが悪意のあるコードを挿入するのを防ぐために、さらに制限が課される場合があります。
__package__
は何をしますか?これは明示的な相対インポートを可能にしますが、特にこの質問と密接な関係はありません-こちらの回答をご覧ください: Pythonの「__package__」属性の目的は何ですか?
モジュール(またはパッケージ)を-mを使用してスクリプトとして実行する主な理由は、特にWindowsでの展開を簡素化するためです。スクリプトは、モジュールが通常行くPythonライブラリの同じ場所にインストールできます-PATHや〜/ .localなどのグローバルな実行可能ディレクトリを汚染する代わりに(ユーザーごとのスクリプトディレクトリを見つけるのは途方もなく難しいです) Windows)。
次に-mと入力するだけで、Pythonがスクリプトを自動的に検索します。たとえば、python -m pip
は、それを実行するPythonインタープリターの同じインスタンスの正しいpipを見つけます。 -mなしで、ユーザーが複数のPythonバージョンをインストールしている場合、どれが「グローバル」ピップになりますか?
ユーザーがコマンドラインスクリプトの「クラシック」エントリポイントを好む場合、これらはPATHのどこかに小さなスクリプトとして簡単に追加できます。または、pipはsetup.pyのentry_pointsパラメーターでインストール時にこれらを作成できます。
したがって、__== '__main__'
を確認し、他の信頼できない実装の詳細を無視してください。