Pythonでは、名前空間パッケージを使用してPythonコードを複数のプロジェクトに分散できます。これは、関連ライブラリを個別のダウンロードとしてリリースする場合に便利です。たとえば、Package-1
PYTHONPATH
のPackage-2
、
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
エンドユーザーはimport namespace.module1
およびimport namespace.module2
を使用できます。
複数のPython製品がその名前空間でモジュールを定義できるように、名前空間パッケージを定義する最良の方法は何ですか?
TL; DR:
Python 3.3では、何もする必要はありません。名前空間パッケージディレクトリに__init__.py
を入れないでください。それが機能するのは3.3です。 pkgutil.extend_path()
ソリューションに対するpkg_resources.declare_namespace()
ソリューション。これは将来の使用に耐え、暗黙のネームスペースパッケージと既に互換性があるためです。
Python 3.3では、暗黙の名前空間パッケージが導入されています。 PEP 42 を参照してください。
これは、import foo
によって作成できる3つのタイプのオブジェクトがあることを意味します。
foo.py
ファイルで表されるモジュール__init__.py
ファイルを含むディレクトリfoo
で表される通常のパッケージ__init__.py
ファイルなしの1つ以上のディレクトリfoo
で表される名前空間パッケージパッケージもモジュールですが、ここでは「モジュール」と言うときは「非パッケージモジュール」を意味します。
まず、sys.path
をスキャンしてモジュールまたは通常のパッケージを探します。成功すると、検索を停止し、モジュールまたはパッケージを作成して初期化します。モジュールまたは通常のパッケージが見つからなかったが、少なくとも1つのディレクトリが見つかった場合、名前空間パッケージを作成して初期化します。
モジュールと通常のパッケージには、__file__
が作成元の.py
ファイルに設定されています。通常パッケージと名前空間パッケージには、__path__
setが作成元のディレクトリに設定されています。
import foo.bar
を実行すると、上記の検索が最初にfoo
に対して行われ、次にパッケージが見つかった場合、bar
の検索は代わりに検索パスとしてfoo.__path__
を使用して行われますsys.path
の。 foo.bar
が見つかった場合、foo
およびfoo.bar
が作成および初期化されます。
では、通常のパッケージと名前空間パッケージはどのように混在しますか?通常はそうではありませんが、古いpkgutil
明示的な名前空間パッケージメソッドは、暗黙的な名前空間パッケージを含むように拡張されています。
次のような__init__.py
を持つ既存の通常のパッケージがある場合:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
...従来の動作は、検索パス上の他のregularパッケージを__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
、path2
およびpath3
がsys.path
にある場合) import package.foo
、import package.bar
、およびimport package.baz
はすべて機能します。
pkg_resources.declare_namespace(__name__)
は、暗黙の名前空間パッケージを含むように更新されていません。
pkgutil と呼ばれる標準モジュールがあり、これを使用して特定の名前空間にモジュールを「追加」できます。
指定したディレクトリ構造で:
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
これらの2行をPackage-1/namespace/__init__.py
とPackage-2/namespace/__init__.py
(*)の両方に配置する必要があります。
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
(*-依存関係を指定しない限り-最初に認識されるのはどれか分からないため-詳細は PEP 42 を参照)
ドキュメント のように:
これにより、パッケージの
__path__
パッケージにちなんだ名前のsys.path
上のディレクトリのすべてのサブディレクトリが追加されます。
これからは、これらの2つのパッケージを個別に配布できるようになります。
要するに、名前空間のコードを__init__.py
に入れ、setup.py
を更新して名前空間を宣言すれば、自由に行くことができます。
これは古い質問ですが、最近誰かが私のブログで名前空間パッケージについての私の投稿がまだ関連しているとコメントしたので、それを実行する方法の実用的な例を提供するので、ここにリンクすると思いました:
これは、何が起こっているかの主な根源についてのこの記事へのリンクです。
http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package
__import__("pkg_resources").declare_namespace(__name__)
トリックは、 TiddlyWeb のプラグインの管理を促進するものであり、これまでのところうまく機能しているようです。