概要
目から鱗の情報だったので、忘れないうちにメモメモ。そういえばそうだわwってなりました。知らなかったのが恥ずかしいですが。そういえば、Github とかでも よく __main__.py
ファイル見かけていました。
__main__.py
を使いましょうって記事です。
__main__
を復習
python やってる人だとほぼ全員以下を書いている or 書いたことがあるはずです。
if __name__ == "__main__": # 処理
python インタープリターは、ファイルを指定されて起動した場合 特殊変数 __name__
に __main__
という値を設定してくれるので、それにより、この スクリプトファイル が他のスクリプトから import されて呼ばれたのか、python インタープリターで直接指定された起動したのかを見分けることが出来るってやつですね。どの本にも書いてある内容です。
んじゃ、__main__.py
があるとどうなる?
上の参照記事でも詳しく書いてくださってますが、__main__.py
をおいておくと、python インタープリターにて
-m オプションでパッケージ指定して起動した際に メインファイル として読み込まれる
ということになります。
どういうときに便利?
簡単な使い捨てスクリプトだと1ファイルなので
$ python hoge.py
とかやって、起動させてしまうのですが、ちょっとしたツール作るときとかはパッケージ構成にすることも多いですね。
例えば
$ tree -L 2 . ├── pkg1 │ ├── __init__.py │ ├── __main__.py │ └── __pycache__ ├── pkg2 │ ├── __init__.py │ ├── __pycache__ │ └── main.py └── venv ├── bin ├── include ├── lib └── pyvenv.cfg
こんな風に pkg1 と pkg2 って構成にしていたとして(ちょっと変ですが説明用ってことで)、pkg1の方には __main__.py
をおいてあります。 pkg2の方は 普通に main.py って名前でファイルおいてあります。中身はこんな感じ。
__main__.py
(pkg1)
print("hello pkg1")
- main.py (pkg2)
if __name__ == "__main__": print("hello pkg2")
pkg1 の場合、-m
オプションつけて呼ぶ場合は、以下のように出来ます。
$ python -m pkg1
pkg2 の場合、以下のようにしないと動いてくれません。
$ python -m pkg2.main
pkg1 と同じように起動してみると
$ python -m pkg2 python: No module named pkg2.__main__; 'pkg2' is a package and cannot be directly executed
って怒られます。
pkg1の場合だと、パッケージ名を指定しているだけなので、個人的にすごい楽。
あと、__main__.py
の場合だと、-m
つけてパッケージ指定された際に呼ばれるのが確定してるので、そもそも
if __name__ == "__main__": # 処理
って書かなくてもいいのも楽。
配布とかしない自前ツールをパッケージ起動する場合とかに便利。
補足
上の例はあくまで -m
オプションつけて呼ぶ場合の話です。setup.py
を作って console_scripts で定義して
$ pip install -e .
とかして使う場合、setup.py
には
entry_points={ 'console_scripts': [ 'pkg1=pkg1.__main__:main' ] }
みたいに関数指定して書く必要があるので __main__.py
には
def main(): pass if __name__ == "__main__": main()
って書いたりします。
python-packaging.readthedocs.io
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場