はじめに
Python で出てくる __main__
についてドキュメントを見ていて、「トップレベルコード環境」というものが出てきて、あんまり詳しくわかっていなかったので気になったので調べたことのメモ書きです。
__main__
について
ドキュメントを読むと、__main__
は以下の2つのために使われる、と記載されていました。*1
- the name of the top-level environment of the program, which can be checked using the name == 'main' expression; and
- the main.py file in Python packages.
__name__ == '__main__'
を使用してトップレベルの環境かどうか確認できるようにすることと、Python パッケージの __main__.py
で利用するもの、とのことでした。
ちなみに先頭と末尾をアンダースコア __
になっているものは、Python の中で予約されているもののようで、メインプログラムを表すものが __main__
が利用されるようです。
トップレベルと __main__
変数
例えば以下のようなディレクトリ構成だった場合には、 main.py
に相当するものを起点に、同一階層のモジュールや、下位の階層の mypackage
のモジュール類を読み込むような形で構成される形が多いと思います。
myproject/ ├─ main.py ├─ hogemodule.py ├─ mypackage/ : ├─ __init__.py ├─ __main__.py ├─ mymodule.py :
Python スクリプトを実行する場合、他の Python スクリプトから import される場合と、何らかで直接 .py
のプログラムを直接実行しる場合があるかと思いますが、直接実行する場合に指定されるモジュール(python3 hogemodule.py
の場合は hogemodule
)がトップレベルコード*2ということになるようです。
ドキュメントによると、主にインタプリタで実行されるケースはトップレベルコードでの実行ということになるらしいです*3。
Python モジュールまたはパッケージがインポートされると、__name__
という変数に Python モジュールの名前に設定されます。 通常、これは .py
の拡張子を除いた Python ファイル自体の名前です。例えば hello.py
の場合は hello
という名前がモジュールとなり、__name__
に設定されます。
ただし、モジュールがトップレベル コード環境で実行される場合、 __name__
変数には、文字列 __main__
が設定されます。
Python3 のインタプリタを呼び出した時
インタプリタを呼び出して __name__
を出力すると、値は __main__
になっています。
% python3 Python 3.7.9 (v3.7.9:13c94747c7, Aug 15 2020, 01:31:08) [Clang 6.0 (clang-600.0.57)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> __name__ '__main__'
直接実行する場合の Python モジュール
適当に以下のようなスクリプトを作成してみます。
#!/usr/local/bin/python3 print(__name__) print("Hello World!!")
ファイル名.py
でモジュールと見なされ、 モジュール名をグローバル変数 __name__
で取得できることが確認できます*4
実行すると __name__
の値は __main__
になっています。
% python3 helloworld.py __main__ Hello World!!
-m オプションで実行される Python モジュールまたはパッケージ
実行してみると、こちらも __name__
の値は __main__
になっています。
% python3 -m helloworld __main__ Hello World!!
標準入力から Python インタプリタへ渡されたコード
読み込んだモジュールはそのままモジュールとして扱われており、標準入力で渡したコード自体は __main__
と判定されているようです。
% echo "import helloworld \nprint(__name__)" | python3 helloworld Hello World!! __main__
-c オプションでのPythonインタプリタに渡されたコード
-c オプションの場合も同様に、読み込んだモジュールはそのままモジュールとして扱われており、標準入力で渡したコード自体は __main__
と判定されているようです。
% python3 -c "import helloworld print(__name__)" helloworld Hello World!! __main__
まとめ
ドキュメントに書いてあることですが、Python の __main__
に関して、以下のことを確認してみました。
- 主に Python インタプリタを利用する場合に指定されるモジュール( ex)
hogehoge.py
)がトップレベルコードとなる - Python モジュールは、ファイルの引数として Python インタプリタに渡される場合や
-m
オプションの引数として指定される場合には__main__
となる - Python パッケージは
-m
オプションの引数として指定される場合には__main__
となる - Python コードは、
-c
オプションや標準入力から Python インタプリタに渡される場合には__main__
となる
モジュールは、自身の __name__
を以下のようなコードでチェックすることで、何らかの形で直接実行されているのか他のモジュール等から呼び出されて実行されているかを判定できるため、テスト時等他のモジュールから Import されずに実行される場合には所定のメソッドを呼び出す、といった場合などに実行させたい処理を記述できます。
if __name__ == '__main__': # exec
参考
*1:https://docs.python.org/ja/3/library/main.html#module-main:title
*2:9. トップレベル要素 — Python 3.12.1 ドキュメント
*3:https://docs.python.org/ja/3/library/main.html#what-is-the-top-level-code-environment:title