2009-11-04 17 views
110

Pythonでは、名前空間パッケージを使用して複数のプロジェクトにPythonコードを配布できます。関連するライブラリを個別のダウンロードとしてリリースする場合に便利です。例えば、ディレクトリPackage-1PYTHONPATHPackage-2Pythonで名前空間パッケージを作成するにはどうすればよいですか?

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製品がその名前空間内のモジュールを定義できるように、名前空間パッケージを定義する最も良い方法は何ですか?

+3

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

答えて

70

と呼ばれますモジュールを指定された名前空間に追加します。

ご提供いただいたディレクトリ構造を持つ

:あなたは両方Package-1/namespace/__init__.pyPackage-2/namespace/__init__.py(*)で、これらの2つの行を置くべき

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

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

(* -unlessので、あなたが述べますそれらの間の依存関係 - 最初に認識されるものがわからない - 詳しくはPEP 420を参照してください)

documentationは言う:これは、パッケージの__path__パッケージにちなんで名付けられたsys.path上のディレクトリのすべてのサブディレクトリに追加されます

今後、この2つのパッケージを個別に配布することができます。要するに

+15

それを__import __( 'pkg_resources')と比較してどのような長所と短所がありますか?declare_namespace(__ name__)? – joeforker

+13

まず、 '__import__'は単純なimport文で簡単に置き換えることができるので、この場合badスタイルと見なされます。 さらに、pkg_resourcesは非標準ライブラリです。それはsetuptoolsに付属しているので、それは問題ではありません。クイックグーグルでは、pkgutilが2.5で導入され、pkg_resourcesがそれより前に導入されたことが明らかになりました。それにもかかわらず、pkgutilは公認された解決策です。実際にはpkg_resourcesの包含はPEP 365で拒否されました。 –

+0

これらの機能はおそらく同じですが、zope.interfaceは両方とも '__init __。py'を使用しているためです。 –

-8

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

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

パッケージ-1を仮定し、パッケージ-2を使用すると、以下を持つことができますが、Pythonパスに入れているファイルシステム上のフォルダです:

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

あなたは今で一つのパッケージnamespaceを持っています2つのモジュールmodule1およびmodule2。そしてあなたは、おそらくフォルダにモジュールを置くべき十分な理由を持っているだけで、その下のようなPythonパスにしていない限り:標準モジュールがあります、あなた は「追加」することができたと、pkgutil

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

私は 'zope.x'のようなものについて話しています。ここでは、関連パッケージの束が別々のダウンロードとしてリリースされています。 – joeforker

+0

しかし、達成しようとしている効果は何ですか。関連パッケージがすべてPYTHONPATHに入っているフォルダの場合、Pythonインタプリタはあなたのために特別な努力をしなくてもそれらを見つけます。 –

+5

PYTHONPATHにPackage-1とPackage-2の両方を追加すると、PythonではPackage-1/namespace /だけが見えます。 –

5

This section should be pretty self-explanatory.

、名前空間を宣言するsetup.pyを更新し、__init__.pyに名前空間のコードを入れて、あなたが行って自由です。

+6

関連リンクが消滅した場合に備えて、リンクの関連部分を常に引用する必要があります。 –

3

これは以前の質問ですが、最近誰かが私のブログに名前空間パッケージについての投稿がまだ関連しているとコメントしていますので、ここにリンクすると思います。

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

__import__("pkg_resources").declare_namespace(__name__)トリックはかなりのドライブです:何が起こっているの主な根性のため、この記事にリンク

http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb

TiddlyWebのプラグインの管理はこれまでのところうまくいくようです。

40

TL; DR:Pythonの3.3で

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


Python 3.3では暗黙の名前空間パッケージが導入されています(PEP 420を参照)。

これはimport fooによって作成できるオブジェクトの3種類が今あることを意味:

  • __init__.pyファイルを含むディレクトリfooで表さfoo.pyファイル
  • 通常のパッケージ、に代表されるモジュール
  • 1つ以上のディレクトリによって表される名前空間パッケージfoo__init__.pyファイルなし

パッケージもモジュールですが、ここでは「モジュール」と言うときは「非パッケージモジュール」を意味します。

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

モジュールと通常のパッケージには、__file__が作成された.pyファイルに設定されています。通常のパッケージと名前空間パッケージは、作成されたディレクトリに__path__が設定されています。

あなたがimport foo.barを行うと上記の検索がfooのために最初に発生したパッケージが見つかった場合、その後、barの検索が代わりにsys.pathの検索パスとしてfoo.__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は(、およびpath1path2path3があなたのsys.pathである)extend_pathラインを持っているようimport package.fooimport package.barimport package.bazはすべて動作します。

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

+2

setuptoolsはどうですか? 'namespace_packages'オプションを使う必要がありますか?そして、['__import__( 'pkg_resources').declare_namespace(__name__)'](http://setuptools.readthedocs.io/en/latest/setuptools.html#namespace-packages)のことは? –

+3

'names.py_packages = ['package']'を 'setup.py'に追加しますか? –

+0

@laurentlaport良い質問です!あなたがPython 3.3以降であれば、私は望んでいませんが、実験して答えに戻ってください。 ;-)私はhttp://setuptools.readthedocs.io/en/latest/setuptools.html#namespace-packagesを見ましたが、更新されていないレガシードキュメントか、それがまだ有効かどうかは不明です。 – clacke

関連する問題