概要
Pythonのパッケージの仕組みは、シンプルな考え方でディレクトリ内に __init__.py
があればパッケージとして認識してくれます。
なのですが、同じパッケージ名で複数のモジュール構造を作ろうとするとエラーになります。
サンプル
以下のような構造(ライブラリが2つあってどっちもutilsパッケージ持ってる)をつくったとして
│ main.py │ ├─lib1 │ └─utils │ __init__.py │ strutils.py │ └─lib2 └─utils __init__.py bytesutils.py
strutils
とbytesutils.py
は以下のような感じとします。
def to_b(s: str) -> bytes: if not isinstance(s, str): raise ValueError('not str') return s.encode('utf-8')
def to_s(b: bytes) -> str: if not isinstance(b, bytes): raise ValueError('not bytes') return b.decode('utf-8')
main.py
は以下ような感じとします。
import sys sys.dont_write_bytecode = True sys.path.extend('lib1 lib2'.split()) from utils.strutils import to_b from utils.bytesutils import to_s s = 'hello world' b = to_b(s) print(f'{type(b)}') s2 = to_s(b) print(f'{type(s2)}')
実行すると以下のエラーとなります。
$ python main.py Traceback (most recent call last): File "main.py", line 7, in <module> from utils.bytesutils import to_s ModuleNotFoundError: No module named 'utils.bytesutils'
で、これを可能にするのが PEP420 -- Implicit Namespace Packages
となります。
python 3.3 から追加された機能となります。
上記ページは英語でいろいろ書いてあるのですが
大事なのは specification の部分のここです。
以下、上記ページから引用。
Namespace packages cannot contain an
__init__.py
.
名前空間パッケージにしたい場合は、__init__.py
を含めてはいけないってことですね。
てことで、先ほどエラーになった構造から __init__.py
を削除します。
│ main.py │ ├─lib1 │ └─utils │ strutils.py │ └─lib2 └─utils bytesutils.py
こうなります。で、再度実行してみる。
$ python main.py <class 'bytes'> <class 'str'>
今度は、ちゃんと動きました。
ちなみに、上記PEPにモジュールの探索パスもちゃんと書いてあります。
以下のようになるとのこと。上記ページより引用。
・If
/foo/ __init__.py
is found, a regular package is imported and returned.・If not, but
/foo.{py,pyc,so,pyd} is found, a module is imported and returned. The exact list of extension varies by platform and whether the -O flag is specified. The list here is representative. ・If not, but
/foo is found and is a directory, it is recorded and the scan continues with the next directory in the parent path. ・Otherwise the scan continues with the next directory in the parent path.
まあ、普段こんなパッケージ構成にはあまりしないと思いますが、最悪必要となった場合に同じパッケージ名でもイケルってのは知っておくと得かも。
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場