Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

272
172

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

__init__.py を省略してはいけない

Last updated at Posted at 2020-01-20

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を送るのはメンテナや他のユーザーに迷惑なのでやめましょう。

272
172
15

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

@methane's pickup articles

klab
モバイルオンラインゲーム、その他スマートフォン関連サービス、及びサーバーインフラ開発・運用
Linked from these articles

Comments

mikan3rd
@mikan3rd
(Edited)

テストを unittest で書いていて、とあるテストがファイル指定だと動作するのに全体でテストを走らせた時には動作しなくて困っていたのですが、原因は __init__.py を書き忘れていた or ファイル名のスペルミス(__init___.py とか)、ということがありました :innocent:

0
emuai
@emuai(ore kuida)

デマを広める記事ではないかと疑っています。
「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.」とも書かれています。
非推奨というニュアンスは感じられない。

0
methane
@methane(Inada Naoki)

それらが言っているのは、 namespace package を提供する手段としては PEP 420 が推奨されるということです。
私が言っているのは、 namespace package は通常の(複数のモジュールを入れるためだけの)パッケージではない、と言うことです。

@emuai さんが書かれたURLの文章を最初から落ち着いて読めば、namespace packageが特定の用途のための機能であることが理解できるはずです。

0
emuai
@emuai(ore kuida)

ご返信ありがとうございます。
しかし謎が増えました。

「特定の用途」とはなんのことですか?
それとも「当文書内に『特定の用途向け』と書かれている」という意味ですか?

「Namespace package とは普通の package ではありません。 特殊な用途のもので、ほとんどの人にとっては 知る必要すらない もの」
という貴殿の記述はPython Packaging User Guide全体を読んだときに貴殿が得た解釈ということでよろしいですか?

0
emuai
@emuai(ore kuida)

少なくともPEP420のほうは、冒頭に「Namespace packages are a mechanism for splitting a single Python package across multiple directories on disk.」とあります。特別な用途に向けたものという感じはしません。

0
methane
@methane(Inada Naoki)
(Edited)

splitting a single Python package across multiple directories on disk.

が特殊な用途なんですよ。通常の Python package は1つのディレクトリです。それを複数のディレクトリに分散させる必要がある場合に使うのが namespace package です。

こっちの最初のセクション(Creating a namespace packageの手前まで)を読めば、どう言う時にそうしたいのかが分かります。

また、その最初のセクションの中に次のように書かれてますよね。

However, namespace packages come with several caveats and are not appropriate in all cases. A simple alternative is to...

namespace packageが有用になる場面ですら、別のシンプルな方法があるよと注意書きされているのです。通常のパッケージで使うのはなおさら推奨できません。

0
emuai
@emuai(ore kuida)

「特定の用途」とか「特殊な用途」というのが何を指してるのかはわかりました。なお自分は「特定の用途」に相当するとは思わないし「普通のpackageではない」とするほど特異とも思わないが言葉のあやでしょうからそこはいいです。
それで結局、 namespace package のみ例外的にimplicit importを認めた、という趣旨かどうかというところが把握できないのですがこれはどこかに書かれていますか?

0
emuai
@emuai(ore kuida)
(Edited)

PEP420のDiscussion節を見ると、私の読み違いでなければ、
・_init_.pyが無いと、その時点でnamespace packageと解釈される
・namespace packageである必要が無いことが確実であるときは__init__.pyを置くことでパフォーマンス上の利点がある。
・namespace package ではパッケージ生成の前にファイル/ディレクトリがスキャンされる。
・_init_.pyが無いことによる ImportWarning は今後はRaiseしない
とのことのようで。

namespace packageが特殊な用法である とか
従来通り__init__.pyを入れろ とか言っている風には感じられないのですが。

0
methane
@methane(Inada Naoki)

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では次のように書かれています。

Directories that lack an init.py file can still be imported, but they're indicative of a special kind of package, known as a "namespace package" (see: PEP 420). Namespace packages are less widely used, so a package that lacks an init.py file is typically meant to be a regular package, and the absence of the init.py file is probably an oversight.
https://docs.astral.sh/ruff/rules/implicit-namespace-package/

逆に、コア開発者やpackaging周りの開発者で、普通のパッケージで __init__.py を省略しても良いと勧めているのを見たことがないのですが、もし知っていたら教えてください。

0
emuai
@emuai(ore kuida)
(Edited)

結局、 regular という単語を見て、regular package こそがスタンダードと解釈された、
そういうことでしょうか。
regular という語を拡大解釈してはいませんか。さらに呼称ですから、字義通りの意味かどうかすら不明では。

はっきりしているのは本家が「__init__.py入りのパッケージをregular package と呼んでいる」それだけです。
「regular packageを使え、意味も無くnamespace package を使うな」
といったことがどこかに書かれているか示されないかぎり
ここの methane 氏の記事の内容が正当なものだとは思いません。

methane氏の考えについては当方も関心はありますが
先に知りたいのは本家のドキュメントになんと書かれているかということです。

0
methane
@methane(Inada Naoki)
(Edited)

公式ドキュメントで、本来の使い方以外をするなって警告を全ての項目の全ての乱用可能性について書いたりはしませんよ。
整数を表すのに必要なく str を使うなとか。確かにそれは禁止されているわけではないですが、啓蒙として「特別な理由がない限り整数にはint型を使え」というのは間違いではないでしょう。

私を含め三人のコア開発者がチュートリアルで __init__.py 抜きのパッケージ作成を書くことを否定して、逆にだれも賛同していないのでも納得できませんか?

1
emuai
@emuai(ore kuida)
(Edited)

書いた本人は無自覚なのかもしれませんが
__init__.pyを置かないで使ってる使用者層に対して「勘違い」だとし、濫用だと非難し、unittestにリクエストするな とか書かれてるのがこの記事です。
これを啓蒙というのですか。

methane氏がかかえている不満の対象とは ほんとうのところは namespace package そのものではないですか。
そして namespace package に対する不満を__init__.py置かない使用者にあてつけているような。

いずれにせよ現状の記事は立場の異なるPython使用者を貶したいだけのように見えます。

0
methane
@methane(Inada Naoki)

私はunittestのPEP 420対応のバグ修正もしましたし、PEP 420の作者もunittestが __init__.py のないディレクトリまで無制限に探索しない方が良いという意見に同意されました。
メンテナンスしている人が、すでに却下されている機能について、「これはよくある勘違いでバグじゃないからバグ報告するな」というのは啓蒙になりませんか?

もちろん、複数の配布パッケージで同一の親パッケージを使いたいケースでのnamespace packageの利用には何の問題も不満もありません。
ですが単にモジュールやサブパッケージを入れる普通のパッケージを作る時に __init__.py を省略するのは、余計なリスクを抱えるだけの濫用です。

濫用とはいえ仕様上禁止されているわけではないので、そんなに使いたいならどうぞ使ってくださいな。

1
atsuoishimoto
@atsuoishimoto
  • PEPをちゃんと読めば書いてありますが、Namespace packageは企業などが特定のディレクトリにパッケージを集めるために作られた仕組みです。それ以外で使う理由はありません。
  • Packaging namespace packagesをちゃんと読めば書いてありますが、「PEP420以前のNamespace packageの仕組みはlegacy」と言っているのであって、通常のパッケージがLegacyなのではありません
  • Namespace packageは遅く、ツールの対応も難しいので使うべきではないというのは単に事実。根拠もなくデマ呼ばわりは謝罪するべきでしょう。
  • PyPIで主要パッケージを眺めてみれば、Namespace packageがどれだけ使われていないかわわかるのでは。
0
atsuoishimoto
@atsuoishimoto

init.pyを置かないで使ってる使用者層に対して「勘違い」だとし、濫用だと非難し、unittestにリクエストするな とか書かれてるのがこの記事です。
これを啓蒙というのですか。

Namespace packageが一般的なPythonの使い方だという誤解を正し、軽挙妄動を慎むように説得する。これこそがまさに啓蒙です。

0

Let's comment your feelings that are more than good

Being held Article posting campaign

272
172

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Login to continue?

Login or Sign up with social account

Login or Sign up with your email address