Python 3.3 から __init__.py を省略して良いと思っている人が多いですが、 省略しないでください。
なぜ勘違いが起こったのか
Python 3.3 から、 PEP 420 で Implicit namespace package が追加されました。
Namespace package とは普通の package ではありません。 特殊な用途のもので、ほとんどの人にとっては 知る必要すらない ものです。
どうしても知りたければ、上の PEP 420 と packaging guide を読んでください。
__init__.py を省略する弊害
普通の package で Implicit namespace package を乱用すると弊害があります。
import が遅くなる
通常の package とは違うので import が package 内のモジュールを探すのが遅くなる可能性があります。
また、確率は低いですがその探索順序の違いによってなにか問題が起こる可能性もあります。
ツールが対応していない
例えば標準ライブラリの unittest で test モジュールを自動で探す機能は __init__.py がないディレクトリの中を探しに行きません。 (https://bugs.python.org/issue29642 を参照)
もし対応しようとしたら、 __init__.py がないディレクトリも全部再帰的に探索しないといけなくなります。そのディレクトリは node_modules で数十万のファイルやディレクトリが入っているかもしれません。そのディレクトリがネットワークマウントされていたりしたらどれだけ遅くなるでしょうか。
Implicit namespace package を通常の package として 乱用するユーザーのためにそんな速度低下は到底受け入れられません。
同じ理由で lint 等のツールでも、自動でパッケージやモジュールを探すような機能が Implicit namespace package を探してくれると期待してはいけません。
背景を知らずに要望を受け入れて対応しているツールもあるかもしれませんが、「対応すべき」「対応しろ」というIssueやPull Requestを送るのはメンテナや他のユーザーに迷惑なのでやめましょう。
Comments
テストを
unittestで書いていて、とあるテストがファイル指定だと動作するのに全体でテストを走らせた時には動作しなくて困っていたのですが、原因は__init__.pyを書き忘れていた or ファイル名のスペルミス(__init___.pyとか)、ということがありましたデマを広める記事ではないかと疑っています。
「Namespace package とは普通の package ではありません。 特殊な用途のもので、ほとんどの人にとっては 知る必要すらない もの」と述べられていますが、
これは packaging guide かどこかに書かれているのですか?
Python Packaging User Guide を見ると、当方の読み違いでなければ、PEP420すなわちimplicit namespace packagesこそが現行のnativeであり、PEP420以前のやり方はlegacy、と言っているのでは?
→ https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#
「Setuptools will search the directory structure for implicit namespace packages by default.」とも書かれています。
非推奨というニュアンスは感じられない。
それらが言っているのは、 namespace package を提供する手段としては PEP 420 が推奨されるということです。
私が言っているのは、 namespace package は通常の(複数のモジュールを入れるためだけの)パッケージではない、と言うことです。
@emuai さんが書かれたURLの文章を最初から落ち着いて読めば、namespace packageが特定の用途のための機能であることが理解できるはずです。
ご返信ありがとうございます。
しかし謎が増えました。
「特定の用途」とはなんのことですか?
それとも「当文書内に『特定の用途向け』と書かれている」という意味ですか?
「Namespace package とは普通の package ではありません。 特殊な用途のもので、ほとんどの人にとっては 知る必要すらない もの」
という貴殿の記述はPython Packaging User Guide全体を読んだときに貴殿が得た解釈ということでよろしいですか?
少なくともPEP420のほうは、冒頭に「Namespace packages are a mechanism for splitting a single Python package across multiple directories on disk.」とあります。特別な用途に向けたものという感じはしません。
が特殊な用途なんですよ。通常の Python package は1つのディレクトリです。それを複数のディレクトリに分散させる必要がある場合に使うのが namespace package です。
こっちの最初のセクション(Creating a namespace packageの手前まで)を読めば、どう言う時にそうしたいのかが分かります。
また、その最初のセクションの中に次のように書かれてますよね。
namespace packageが有用になる場面ですら、別のシンプルな方法があるよと注意書きされているのです。通常のパッケージで使うのはなおさら推奨できません。
「特定の用途」とか「特殊な用途」というのが何を指してるのかはわかりました。なお自分は「特定の用途」に相当するとは思わないし「普通のpackageではない」とするほど特異とも思わないが言葉のあやでしょうからそこはいいです。
それで結局、 namespace package のみ例外的にimplicit importを認めた、という趣旨かどうかというところが把握できないのですがこれはどこかに書かれていますか?
PEP420のDiscussion節を見ると、私の読み違いでなければ、
・_init_.pyが無いと、その時点でnamespace packageと解釈される
・namespace packageである必要が無いことが確実であるときは__init__.pyを置くことでパフォーマンス上の利点がある。
・namespace package ではパッケージ生成の前にファイル/ディレクトリがスキャンされる。
・_init_.pyが無いことによる ImportWarning は今後はRaiseしない
とのことのようで。
namespace packageが特殊な用法である とか
従来通り__init__.pyを入れろ とか言っている風には感じられないのですが。
PEPは機能提案のための文書なので、namespace packageが何のためにあって、どう言う場面で使うべきでないかなど、一般Pythonユーザー向けの説明はされていません。(最近のPEPは How to teach this セクションがありますが。)
しかし、通常のパッケージを reguler package と呼んでいるところからも分かる通り、namespace packageはregularではありません。
通常のパッケージで
__init__.pyを省略し namespace package を使うことは、別に禁止はされていませんが、さまざまな問題を引き起こします。分かりやすい例はこの記事ですでに説明しましたが、探せば他にも見つかります。例えば、複数のディレクトリの内容を混ぜるのですから、意図せずに混ざったら問題なのは自明ですよね?私以外のコア開発者が書いた罠の一覧もあります。cpythonやpytestのissuesを"namespace package"で検索してみても良いでしょう。それなのに、namespace packageが何のための機能なのかを知らないまま、「Python 3.3からは
__init__.pyがいらない」という雑な紹介が多かったので、初心者が不要な問題に引っかからないための啓蒙としてこの記事を書きました。例えばこの issue は、典型的な誤解をしているユーザーがチュートリアルを更新して
__init__.pyが不要だと追記しようという提案をしているもので、私を含めて三人のコア開発者が初心者向きのものではないと反対しているものです。また、 ruff にも含まれている flake8-no-pep420 というlinterでは次のように書かれています。
逆に、コア開発者やpackaging周りの開発者で、普通のパッケージで
__init__.pyを省略しても良いと勧めているのを見たことがないのですが、もし知っていたら教えてください。結局、 regular という単語を見て、regular package こそがスタンダードと解釈された、
そういうことでしょうか。
regular という語を拡大解釈してはいませんか。さらに呼称ですから、字義通りの意味かどうかすら不明では。
はっきりしているのは本家が「__init__.py入りのパッケージをregular package と呼んでいる」それだけです。
「regular packageを使え、意味も無くnamespace package を使うな」
といったことがどこかに書かれているか示されないかぎり
ここの methane 氏の記事の内容が正当なものだとは思いません。
methane氏の考えについては当方も関心はありますが
先に知りたいのは本家のドキュメントになんと書かれているかということです。
公式ドキュメントで、本来の使い方以外をするなって警告を全ての項目の全ての乱用可能性について書いたりはしませんよ。
整数を表すのに必要なく str を使うなとか。確かにそれは禁止されているわけではないですが、啓蒙として「特別な理由がない限り整数にはint型を使え」というのは間違いではないでしょう。
私を含め三人のコア開発者がチュートリアルで
__init__.py抜きのパッケージ作成を書くことを否定して、逆にだれも賛同していないのでも納得できませんか?書いた本人は無自覚なのかもしれませんが
__init__.pyを置かないで使ってる使用者層に対して「勘違い」だとし、濫用だと非難し、unittestにリクエストするな とか書かれてるのがこの記事です。
これを啓蒙というのですか。
methane氏がかかえている不満の対象とは ほんとうのところは namespace package そのものではないですか。
そして namespace package に対する不満を__init__.py置かない使用者にあてつけているような。
いずれにせよ現状の記事は立場の異なるPython使用者を貶したいだけのように見えます。
私はunittestのPEP 420対応のバグ修正もしましたし、PEP 420の作者もunittestが
__init__.pyのないディレクトリまで無制限に探索しない方が良いという意見に同意されました。メンテナンスしている人が、すでに却下されている機能について、「これはよくある勘違いでバグじゃないからバグ報告するな」というのは啓蒙になりませんか?
もちろん、複数の配布パッケージで同一の親パッケージを使いたいケースでのnamespace packageの利用には何の問題も不満もありません。
ですが単にモジュールやサブパッケージを入れる普通のパッケージを作る時に
__init__.pyを省略するのは、余計なリスクを抱えるだけの濫用です。濫用とはいえ仕様上禁止されているわけではないので、そんなに使いたいならどうぞ使ってくださいな。
Namespace packageが一般的なPythonの使い方だという誤解を正し、軽挙妄動を慎むように説得する。これこそがまさに啓蒙です。
Let's comment your feelings that are more than good