__main__.pyってなに
時折、見かける「__main__.py」 ってなにか調べてみました。
python -mで実行したときに呼ばれる
「python -m パッケージ名」を実行するとそのパーケージの__main__.pyが呼ばれます。
パッケージの作り方によっては__main__.py以外のモジュールを呼び出すことも可能なようです。
なぜpython -mを使うの?
setup.pyでentry_points/console_scriptsを定義すればパッケージ名のみで実行できます。
https://architecting.hateblo.jp/entry/2020/12/24/173311
なのになぜpython -mでパッケージを実行するのでしょう?調査にもっとも苦労したのがここです。憶測を含んでいます。
python -mを使うパッケージの例として有名なものを挙げます。
- unittest
- json.tool
- htttp.server
これらはいずれも「ライブラリ」であり「ツール」でもあります。
unittestはテストコードを記述するためのライブラリであると同時にテストコードを探索、実行、結果報告するツールでもあります。
json.toolはJSON形式を扱うライブラリであると同時にJSONファイルを整形するツールです。
http.serverはWebサーバを記述するためのライブラリであると同時に簡易なWebサーバを立ち上げるツールです。
このように一つのパッケージがライブラリとツールの両方の機能を提供しているときに、ライブラリとして利用する場合はimport、ツールとして利用する場合はpython -mで呼び出すのがPython界隈の慣例のようです。
そのようなパッケージのsetup.pyではentry_points/console_scriptsは定義しないようです。実際、上記3つのツールはいずれもpython -mなしでは実行できません。ライブラリ利用者が誤ってツール機能を実行してしまうことを防止しているのかと推測します。
私的まとめ
- ライブラリとツールの両方を一つのパッケージで提供するとき__main__.pyを使う
- このときsetup.pyではentry_points/console_scriptsは定義しない
- ライブラリ利用者はimportで利用する
- ツール利用者はpython -mで利用する
- ライブラリ機能しか提供しないパッケージでは__main__.pyは使わない
- 誤ってpython -mで実行されると困る
- ツール機能しか提供しないパッケージでは__main__.pyは使わない
おまけ
python -m hogeとpython hoge.__main__.pyの違いは__package__にパッケージ名が入るかNoneが入るかのだけのようです。処理上は差がないと言えると思います。