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


141

Pythonでは、名前空間パッケージを使用すると、Pythonコードを複数のプロジェクトに分散できます。これは、関連するライブラリを個別のダウンロードとしてリリースする場合に便利です。たとえば、ディレクトリとPackage-1Package-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.module1import namespace.module2

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


5
module1とmodule2は実際にはモジュールではなくサブパッケージのように見えます。私が理解しているように、モジュールは基本的に単一のファイルです。たぶん、subpkg1とsubpkg2は名前としてより意味がありますか?
アラン14

回答:


79

TL; DR:

Python 3.3では、何もする必要はありません__init__.py。名前空間パッケージディレクトリに何も配置しないでください。これで問題なく動作します。3.3より前のバージョンでは、将来性があり、暗黙の名前空間パッケージと既に互換性があるためpkgutil.extend_path()pkg_resources.declare_namespace()1 つよりもソリューションを選択してください。


Pythonの3.3を発表、暗黙的な名前空間のパッケージは、参照PEP 420

これは、によって作成できるオブジェクトのタイプが3つあることを意味しますimport foo

  • foo.pyファイルで表されるモジュール
  • ファイルfooを含むディレクトリで表される通常のパッケージ__init__.py
  • ファイルfooなしの1つ以上のディレクトリで表される名前空間パッケージ__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

...そして限り、2のように__init__.py持ってextend_path行を(とpath1path2そしてpath3自分の中にあるsys.pathimport package.fooimport package.barおよびimport package.bazすべての作業はなります。

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


2
setuptoolsはどうですか?namespace_packagesオプションを使用する必要がありますか?そして、__import__('pkg_resources').declare_namespace(__name__)事は?
kawing-chiu 2016

3
追加する必要namespace_packages=['package']がありsetup.pyますか?
Laurent LAPORTE 2016年

1
@clacke:を使用するとnamespace_packages=['package']、setup.pyはnamespace_packages.txtEGG-INFOにを追加します。それでも影響がわかりません…
Laurent LAPORTE

1
@ kawing-chiu pkg_resources.declare_namespaceover の利点はpkgutil.extend_path、監視を続けることsys.pathです。このようにsys.pathして、名前空間のパッケージが最初に読み込まれた後に新しいアイテムが追加された場合、その新しいパスアイテムの名前空間のパッケージを引き続き読み込むことができます。(__import__('pkg_resources')over を使用する利点import pkg_resourcesは、最終的にとしpkg_resourcesて公開されないことですmy_namespace_pkg.pkg_resources。)
Arthur Tacca

1
@clackeそれはそのようには機能しません(しかし、それはあたかも同じように効果があります)。この関数で作成されたすべてのパッケージ名前空間のグローバルリストを保持し、を監視しsys.pathます。ときにsys.pathそれが影響する場合にそれをチェックを変更する__path__任意の名前空間のを、そしてそれがないならば、それは、それらの更新__path__プロパティを。
Arthur Tacca 2017年

81

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 420をしてください)

などのドキュメント言います:

これにより、パッケージの__path__ディレクトリのすべてのサブディレクトリに追加されますsys.path名前付きのます。

これで、これら2つのパッケージを個別に配布できるようになります。


17
それとimport __( 'pkg_resources')。declare_namespace(__ name)を使用する場合の長所と短所は何ですか?
joeforker 2009年

14
1つ目は、__import__プレーンなインポートステートメントで簡単に置き換えることができるため、この場合はスタイルが悪いと見なされます。さらに言えば、pkg_resourcesは非標準ライブラリです。setuptoolsが付属しているため、問題はありません。すばやくグーグルすると、pkgutilが2.5で導入され、pkg_resourcesがそれよりも古いことがわかります。それにもかかわらず、pkgutilは一般に認められたソリューションです。pkg_resources包含は、実際には、PEP 365で拒否された
マイク・Hordecki

3
PEP 382からの引用:名前空間パッケージへの現在の必須のアプローチは、名前空間パッケージを提供するための複数のわずかに互換性のないメカニズムにつながりました。たとえば、pkgutilは* .pkgファイルをサポートしています。setuptoolsはサポートしていません。同様に、setuptoolsはzipファイルの検査をサポートし、その_namespace_packages変数への部分の追加をサポートしますが、pkgutilはサポートしません。
ドレイクグアン

7
これらの2行は、両方のファイルに入れることがはずの:Package-1/namespace/__init__.py Package-2/namespace/__init__.py私たちが最初にリストされたパッケージディレクトリを知っていないことを提供しますか?
ブラ2013

3
@ChristofferKarlssonはい、それがポイントです。どちらが最初かを知っていても大丈夫ですが、実際の問題は、それがどのような状況でも、つまり他のユーザーにとって最初であることを保証できるかどうかです。
Bula 2013


2

これは古い質問ですが、名前空間パッケージに関する私の投稿はまだ関連があると最近誰かが私のブログにコメントしたので、それを実行する方法の実用的な例を提供しているので、ここにリンクすると思いました:

https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb

これは、何が起こっているのかという主要な根拠について、この記事にリンクしています。

http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package

__import__("pkg_resources").declare_namespace(__name__)トリックはかなりのドライブでのプラグインの管理でTiddlyWebと、これまでに出て動作しているようです。


-9

あなたはPython名前空間の概念を前後に持っています、Pythonではパッケージをモジュールに入れることはできません。パッケージには、その逆ではないモジュールが含まれています。

Pythonパッケージは、単に__init__.pyファイルを含むフォルダーです。モジュールとは、パッケージ内(または直接PYTHONPATH)の他のファイルで、.py拡張子が付いています。したがって、例では2つのパッケージがありますが、モジュールは定義されていません。パッケージがファイルシステムフォルダーであり、モジュールがファイルであると考えると、パッケージにモジュールが含まれているのではなく、その逆の理由がわかります。

したがって、例では、Package-1とPackage-2が、Pythonパスに配置したファイルシステム上のフォルダーであると想定すると、次のようになります。

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

これでnamespace、2つのモジュールmodule1と1つのパッケージが作成されましたmodule2。そして、十分な理由がない限り、モジュールをフォルダーに入れて、以下のようにそれだけをpythonパスに置く必要があります。

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

zope.x関連パッケージの束が個別のダウンロードとしてリリースされる場所などについて話している。
joeforker 2009年

わかりました、しかしあなたが達成しようとしている効果は何ですか。PYTHONPATH上のすべての関連パッケージが含まれているフォルダーの場合、Pythonインタープリターは余分な労力なしでそれらを見つけます。
Tendayi Mawushe 2009年

5
Package-1とPackage-2の両方をPYTHONPATHに追加すると、Package-1 / namespace /のみがPythonに表示されます。
セーレンLøvborg
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.