プログラミング初心者がアーキテクトっぽく語る

見苦しい記事も多数あるとは思いますが訂正しつつブログと共に成長していければと思います

__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は使わない
    • entry_points/console_scriptsを定義してPATHを通した方がpython -mよりもCLI利用者の利便性が高い
    • CLIからの実行方式を2つ提供する意味がない
    • でもプログラムのエントリポイントがわかりやすいというメリットはあるかもしれない

おまけ

python -m hogepython hoge.__main__.pyの違いは__package__にパッケージ名が入るかNoneが入るかのだけのようです。処理上は差がないと言えると思います。