Python で名前空間パッケージを作成するにはどうすればよいですか?
-
16-09-2019 - |
質問
Python では、名前空間パッケージを使用して、Python コードを複数のプロジェクトに分散できます。これは、関連するライブラリを個別のダウンロードとしてリリースする場合に便利です。たとえば、ディレクトリの場合 Package-1
そして Package-2
で PYTHONPATH
,
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()
1 つは、将来性があり、暗黙的な名前空間パッケージとすでに互換性があるためです。
Python 3.3 では、暗黙的な名前空間パッケージが導入されています。「」を参照してください。 PEP420.
これは、現在 3 種類のオブジェクトを作成できることを意味します。 import foo
:
- で表されるモジュール
foo.py
ファイル - ディレクトリで表される通常のパッケージ
foo
を含む__init__.py
ファイル - 1 つ以上のディレクトリで表される名前空間パッケージ
foo
何もなしで__init__.py
ファイル
パッケージもモジュールですが、ここで「モジュール」というときは「非パッケージモジュール」を意味します。
まずスキャンします sys.path
モジュールまたは通常のパッケージの場合。成功すると、検索が停止され、モジュールまたはパッケージが作成されて初期化されます。モジュールまたは通常のパッケージは見つからなかったが、少なくとも 1 つのディレクトリが見つかった場合は、名前空間パッケージを作成して初期化します。
モジュールと通常のパッケージには、 __file__
に設定します .py
作成元のファイル。通常のパッケージと名前空間パッケージには、 __path__
作成元のディレクトリに設定されます。
そうするとき 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__)
...従来の動作では、他のものを追加します。 通常 検索されたパス上のパッケージ __path__
. 。ただし、Python 3.3 では、名前空間パッケージも追加されます。
したがって、次のディレクトリ構造を持つことができます。
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
...そして二人がいる限り __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__)
(* なぜなら、それらの間の依存関係を明示しない限り、どちらが最初に認識されるかはわかりません。参照してください。 PEP420 詳細については)
として ドキュメンテーション 言います:
これにより、パッケージに追加されます
__path__
ディレクトリのすべてのサブディレクトリsys.path
パッケージにちなんで名付けられました。
今後は、これら 2 つのパッケージを個別に配布できるようになります。
要するに、名前空間を宣言する__init__.py
を更新し、setup.py
で名前空間のコードを入れて、あなたが行くことは自由です。
この古い質問ですが、誰かが最近名前空間のパッケージについての私の投稿はまだ関連だったので、それはそれが行くようにする方法の実用的な例を提供して、私はここでそれにリンクするだろうと思った私のブログにコメントします:
<のhref = "https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb" のrel = "nofollowをnoreferrer "> https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb の
これは何が起こっているの主な根性のため、この記事にリンクします:
http://www.siafoo.net/article / 77#複数のディストリビューションワン仮想パッケージの
__import__("pkg_resources").declare_namespace(__name__)
トリックはかなりドライブ TiddlyWeb の中のプラグインの管理で、これまでに出て動作しているようです。
あなたは後ろから前に、あなたのPythonの名前空間の概念を持っている、それがモジュールにパッケージを置くためにpythonでは不可能です。パッケージは、他の方法で回避モジュールがない含まれています。
Pythonパッケージは、単に__init__.py
ファイルを含むフォルダです。モジュールはPYTHONPATH
拡張子を持つ(.py
に直接又は)他のパッケージ内のファイルです。だからあなたの例では、次の2つのパッケージを持っていますが、何のモジュールが定義されていません。あなたは、パッケージがファイルシステムフォルダで、モジュールがファイルであることを考えると、パッケージが他の方法で回避モジュールが含まれていない理由は、あなたが見ています。
あなたの例ではパッケージ-1およびパッケージ-2を想定したので、あなたが次を持つことができますPythonのパスに置かれているファイルシステム上のフォルダです。
Package-1/
namespace/
__init__.py
module1.py
Package-2/
namespace/
__init__.py
module2.py
これで、二つのモジュールのnamespace
とmodule1
と1パッケージmodule2
を持っています。そしてあなたは、おそらくフォルダにモジュールを置くべき十分な理由を持っており、以下のようなpythonのパスにのみそれを持っている場合を除きます:
Package-1/
namespace/
__init__.py
module1.py
module2.py