はじめに
七尾百合子さん、お誕生日 309日目 おめでとうございます! nikkieです。
プライベートでの Python パッケージ開発からの学びです。
目次
- はじめに
- 目次
- 結論:パッケージをpython -mに渡すには__main__.pyが要る
- 全て書いてあったpython -mのドキュメント
- 経験した事象:モジュールをパッケージにしたらpython -mで動かない
- __main__.pyにはif文不要
- 終わりに
結論:パッケージをpython -mに渡すには__main__.pyが要る
以下のようにパッケージを実行したい時
python -m mypkg.awesome python -m mypkg.fabulous
以下のような構造が必要です
mypkg/
├── __init__.py
├── awesome.py # python -m mypkg.awesome で(__main__を)実行
└── fabulous/
├── __init__.py
└── __main__.py # python -m mypkg.fabulous で実行
python -mに渡すものがモジュール(.pyファイル)かパッケージ(__init__.pyを置いたディレクトリ)かで、要求されるものが異なることを学びました
全て書いてあったpython -mのドキュメント
https://docs.python.org/ja/3/using/cmdline.html#cmdoption-m
-m <module-name>
sys.path から指定されたモジュール名のモジュールを探し、その内容を __main__ モジュールとして実行します。引数は module 名なので、拡張子 (
.py) を含めてはいけません。(略)パッケージ名 (名前空間パッケージも含む) でも構いません。通常のモジュールの代わりにパッケージ名が与えられた場合、インタプリタは
<pkg>.__main__を main モジュールとして実行します。
経験した事象:モジュールをパッケージにしたらpython -mで動かない
元々python -m recent_state_summarizer.fetchと実行できていました。
recent_state_summarizer/ ├── __init__.py └── fetch.py
fetch.pyには、__main__(トップレベル環境)となる場合のコードが書かれていました。
ref: https://docs.python.org/ja/3/library/__main__.html#what-is-the-top-level-code-environment
if __name__ == "__main__": cli()
このfetch.pyが肥大化してきたので、fetch パッケージを導入しました。
fetch.pyをfetch/__init__.pyとするだけで、既存の import を壊さずにfetchディレクトリが導入できます
recent_state_summarizer/
├── __init__.py
└── fetch/
└── __init__.py
fetch/__init__.pyに__main__となる場合のコードを残していたのですが、python -m recent_state_summarizer.fetchと実行できなくなりました。
'recent_state_summarizer.fetch' is a package and cannot be directly executed
この理由ですが、python -mのドキュメントにあるように、fetch/__main__.pyが必要なためと学びました
recent_state_summarizer/
├── __init__.py
└── fetch/
├── __init__.py
+ └── __main__.py
__main__.pyにはif文不要
https://docs.python.org/ja/3/library/__main__.html#id1
The content of
__main__.pytypically isn't fenced with anif __name__ == '__main__'block.
Instead, those files are kept short and import functions to execute from other modules.
__main__.pyにはif __name__ == '__main__'は不要。
他のモジュールから関数を import して短く保つ
つまり以下だけでよいということです。
if文を書かなくても伝わります(__main__とならない場合がありません)
# import文の例示は省略
cli()
終わりに
python -mにパッケージ名を指定した時、__main__.pyが実行されます。
python -mで実行していたモジュールをパッケージに変えた時、__main__.pyも用意しないとpython -mでの実行だけ壊してしまいます(俺みたいになるな!)。
__main__.pyはトップレベル環境__main__として実行されるものなので、if __name__ == '__main__'は不要で短く済ませます。
過去にpython -mとsys.pathの関係を書きましたが、__main__.pyとの関係で本記事が爆誕しました