今日まで、一部のパッケージで定義されている__path__
属性に気づかなかった。ドキュメントによると:
パッケージは、もう1つの特別な属性
__path__
をサポートしています。これは、そのファイルのコードが実行される前に、パッケージの__init__.py
を保持するディレクトリの名前を含むリストに初期化されます。この変数は変更できます。これにより、パッケージに含まれるモジュールおよびサブパッケージの今後の検索に影響します。この機能は多くの場合必要ありませんが、パッケージにあるモジュールのセットを拡張するために使用できます。
誰かが私にこれが正確に何を意味するのか、なぜ私がそれを使いたいのか説明してくれませんか?
これは通常、パッケージをディスク全体に配置するために pkgutil とともに使用されます。たとえば、zope.interfaceとzope.schemaは別々のディストリビューションです(zope
は「名前空間パッケージ」です)。 _/usr/lib/python2.6/site-packages/zope/interface/
_でzope.schemaをローカルで使用しているときに、_/home/me/src/myproject/lib/python2.6/site-packages/zope/schema
_にzope.interfaceがインストールされている可能性があります。
_/usr/lib/python2.6/site-packages/zope/__init__.py
_にpkgutil.extend_path(__path__, __name__)
を配置すると、pkgutilで___path__
_が_['/usr/lib/python2.6/site-packages/zope', '/home/me/src/myproject/lib/python2.6/site-packages/zope']
_に変更されるため、zope.interfaceとzope.schemaの両方がインポート可能になります。
_pkg_resources.declare_namespace
_(Setuptoolsの一部)は_pkgutil.extend_path
_に似ていますが、パス上のzipをより認識しています。
手動で___path__
_を変更することは一般的ではなく、おそらく必要ではありませんが、名前空間パッケージのインポート問題をデバッグするときに変数を確認することは役立ちます。
サルパッチングに___path__
_を使用することもできます。たとえば、_distutils/__init__.py
_の初期のファイル_sys.path
_を作成して、distutilsにサルパッチを適用することがあります。
_import os
stdlib_dir = os.path.dirname(os.__file__)
real_distutils_path = os.path.join(stdlib_dir, 'distutils')
__path__.append(real_distutils_path)
execfile(os.path.join(real_distutils_path, '__init__.py'))
# and then apply some monkeypatching here...
_
__path__
を変更すると、インタープリターに、そのパッケージに属するモジュールを別のディレクトリで探すように強制できます。
これにより、たとえば、ランタイム条件に基づいて、同じモジュールの異なるバージョンをロードできます。異なるプラットフォームで同じ機能の異なる実装を使用したい場合は、これを行うことがあります。
構文 が示すように、ランタイム条件に基づいてモジュールの異なるバージョンを選択することに加えて、この機能により、単一の論理の外観を維持しながら、パッケージを複数の部分/ダウンロード/インストールに分割することもできますパッケージ。
以下を検討してください。
mypkg
と_mypkg_foo
の2つのパッケージがあります。_mypkg_foo
には、mypkg
、foo.py
へのオプションモジュールが含まれています。mypkg
にはfoo.py
が含まれていません。mypkg
の__init__.py
は次のように実行できます。
try:
import _mypkg_foo
__path__.append(os.path.abspath(os.path.dirname(_mypkg_foo.__file__)))
import mypkg.foo
except ImportError:
pass
誰かがパッケージ_mypkg_foo
をインストールしている場合、mypkg.foo
を利用できます。存在しない場合は存在しません。
私が遭遇した特定の状況は、パッケージが大きくなり、それを参照するコードを変更せずに、パッケージの一部をサブディレクトリに分割したい場合です。
たとえば、私はviews
というパッケージを使用しています。このパッケージは、パッケージの主要なトップレベルの目的と混同されていたいくつかのサポートユーティリティ関数を収集していました。これらのサポート関数をサブディレクトリutils
に移動し、views
パッケージの__init__.py
に次の行を追加できました。
__path__.append(os.path.join(os.path.dirname(__file__), "utils"))
この変更もviews/__init_.py
で、ファイルをさらに変更することなく、残りのソフトウェアを新しいファイル構造で実行できました。
(views/__init__.py
ファイルのimport
ステートメントで同様のことを実行しようとしましたが、view
パッケージのインポートを通じてサブパッケージモジュールがまだ表示されていません-私は私がそこに何か足りないのかどうかは完全にはわかりません。その歓迎についてのコメント!)
(Python 2.7インストールに基づくこの応答)