1. ホーム
  2. python

[解決済み] Pythonで名前空間パッケージを作成するにはどうすればよいですか?

2022-04-28 06:30:46

質問

Pythonでは、名前空間パッケージを使用すると、Pythonのコードを複数のプロジェクトに分散させることができます。これは、関連するライブラリを別々のダウンロードとしてリリースしたい場合に便利です。例えば、ディレクトリ Package-1Package-2PYTHONPATH ,

Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py

エンドユーザは import namespace.module1import namespace.module2 .

複数のPython製品がその名前空間のモジュールを定義できるように、名前空間パッケージを定義する最良の方法は何でしょうか?

どのように解決するのですか?

TL;DR。

Python 3.3 では、何もする必要はありません。 __init__.py を名前空間パッケージのディレクトリに配置すれば、そのまま動作します。3.3 より前のバージョンでは pkgutil.extend_path() という解決策を pkg_resources.declare_namespace() は、将来性があり、暗黙的な名前空間パッケージとすでに互換性があるからです。


Python 3.3では暗黙の名前空間パッケージが導入され、以下のようになります。 PEP 420 .

これはつまり、現在では import foo :

  • で表されるモジュールは foo.py ファイル
  • 通常のパッケージで、ディレクトリで表される foo を含む __init__.py ファイル
  • 1つまたは複数のディレクトリで表される名前空間パッケージ foo を一切使用せず __init__.py ファイル

パッケージもモジュールですが、ここで言うモジュールとは、quot;非パッケージモジュールという意味です。

最初にスキャンするのは sys.path を指定します。もし成功したら、検索をやめて、モジュールやパッケージを作成し、初期化します。モジュールや通常のパッケージは見つからなかったが、少なくとも一つのディレクトリが見つかった場合、名前空間パッケージを作成し、初期化する。

モジュールと通常のパッケージは __file__ に設定します。 .py ファイルから作成されます。通常のパッケージとネームスペース・パッケージには __path__ には、それらが作成されたディレクトリまたはディレクトリが設定されます。

を実行すると import foo.bar の場合、上記の検索が最初に行われます。 foo を検索し、パッケージが見つかれば barfoo.__path__ の代わりに検索パスとして sys.path . もし foo.bar が見つかります。 foofoo.bar が作成され、初期化されます。

では、通常のパッケージと名前空間パッケージはどのように混ざり合うのでしょうか?通常は混ざらないのですが、昔の pkgutil 明示的な名前空間パッケージのメソッドが拡張され、暗黙的な名前空間パッケージが含まれるようになりました。

既存の通常パッケージに __init__.py このように

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

... レガシーな動作は、他の任意の 正規 パッケージは、検索されたパス上の __path__ . しかし、Python 3.3では、名前空間パッケージも追加されています。

そのため、以下のようなディレクトリ構成にすることができます。

├── path1
│   └── package
│       ├── __init__.py
│       └── foo.py
├── path2
│   └── package
│       └── bar.py
└── path3
    └── package
        ├── __init__.py
        └── baz.py

... そして、2つの __init__.py には extend_path の行(と path1 , path2path3 はあなたの sys.path ) import package.foo , import package.barimport package.baz はすべて動作します。

pkg_resources.declare_namespace(__name__) は、暗黙の名前空間パッケージを含むように更新されていません。