19

「アドオン」を個別のパッケージとして作成する Python フレームワークを開発しています。すなわち:

import myframework
from myframework.addons import foo, bar

今、私が調整しようとしているのは、これらのアドオンをコア フレームワークとは別に配布し、myframework.addons名前空間に挿入できるようにすることです。

現在、これに対する私の最善の解決策は次のとおりです。アドオンがデプロイされます (ほとんどの{python_version}/site-packages/場合、次のようになります:

fooext/
fooext/__init__.py
fooext/myframework/
fooext/myframework/__init__.py
fooext/myframework/addons/
fooext/myframework/addons/__init__.py
fooext/myframework/addons/foo.py

にはfooext/myframework/addons/__init__.py、pkgutil パス拡張コードがあります。

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

問題は、これが機能するために PYTHONPATH が含まれている必要があることfooext/ですが、それが持つ唯一のものは親インストールディレクトリ (ほとんどの場合、上記のsite-packages) です。

myframework/addons/__init__.pyこれに対する解決策は、myframework サブパッケージを含むモジュールをトラバースして検索する追加のコードを用意することです。sys.pathこの場合、それを追加するsys.pathとすべてが機能します。

私が持っていた別のアイデアは、アドオンファイルをインストール場所に直接書き込むことですmyframework/addons/が、そうすると、開発と展開された名前空間が異なってしまいます。

これを達成するためのより良い方法、または上記の配布の問題に対する別のアプローチはありますか?

4

5 に答える 5

7

名前空間パッケージを参照してください:

http://www.python.org/dev/peps/pep-0382/

または setuptools で:

http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages

于 2009-11-12T02:27:51.733 に答える
4

Setuptools には、パッケージの「エントリ ポイント」(関数、オブジェクトなど) を名前で検索する機能があります。Trac はこのメカニズムを使用してプラグインをロードしますが、うまく機能します。

于 2009-01-19T05:35:28.273 に答える
4

これを達成するためのより良い方法、または上記の配布の問題に対する別のアプローチはありますか?

おそらく。Python のモジュール/パッケージのセットアップは、一般的にこのように動的に改ざんするのは難しいですが、そのオブジェクト/クラス システムはオープンであり、明確に定義された方法で拡張可能です。モジュールとパッケージに、プロジェクトを適切にカプセル化するために必要な機能がまったくない場合は、代わりにクラスを使用できます。

たとえば、完全に異なるパッケージに拡張機能を含めることができますが、特定のインターフェイスを介して基本フレームワークにクラスを挿入できます。例えば。基本的なアプリケーション ラッパーを含む myframework/_ _ init _ _.py:

class MyFramework(object):
    """A bare MyFramework, I only hold a person's name
    """
    _addons= {}
    @staticmethod
    def addAddon(name, addon):
        MyFramework._addons[name]= addon

    def __init__(self, person):
        self.person= person
        for name, addon in MyFramework._addons.items():
            setattr(self, name, addon(self))

次に、「所有者」または「外部」の MyFramework クラス インスタンスへの参照を保持する myexts/helloer.py に拡張機能を含めることができます。

class Helloer(object):
    def __init__(self, owner):
        self.owner= owner
    def hello(self):
        print 'hello '+self.owner.person

import myframework
myframework.MyFramework.addAddon('helloer', Helloer)

したがって、「myframework をインポートする」だけでは、基本的な機能しか得られません。ただし、「myexts.helloer もインポート」すると、MyFramework.helloer.hello() を呼び出すこともできます。当然ながら、アドオンが基本的なフレームワークの動作や相互に作用するためのプロトコルを定義することもできます。そのレベルの複雑さが必要な場合は、他のアプリケーションに影響を与える可能性のあるクラスにモンキー パッチを適用することなく、フレームワークのサブクラスがオーバーライドしてカスタマイズできる内部クラスなどを実行することもできます。

このように動作をカプセル化することは便利ですが、通常、このモデルに適合するように既に持っているモジュール レベルのコードを適応させるのは煩わしい作業です。

于 2009-01-18T15:01:30.703 に答える
0

あなたが求めていることは、インポートフックを使用して非常にきれいに達成できるようです。

これは、Python のデフォルトの読み込みメカニズムを使用するのではなく、すべてのサブパッケージとモジュールの読み込みを実行するために、パッケージ (またはあなたの場合はフレームワーク) に関連付けることができるカスタム読み込みコードを作成する方法です。次に、基本パッケージとして、またはフレームワークの下にローダーをサイトパッケージにインストールできます。

パッケージがローダーに関連付けられていることが判明した場合 (必要に応じて、相対パスにハードコードすることができます)、たとえば、常にローダーを使用してすべてのアドオンを読み込みます。これには、PYTHONPATH をいじる必要がないという利点があります。これは、一般に、できるだけ短くしておく価値があります。

これに代わる方法は、initファイルを使用して、サブモジュールのインポート呼び出しを、取得したいモジュールにリダイレクトすることですが、これは少し面倒です。

インポート フックの詳細については、次を参照してください。

http://www.python.org/dev/peps/pep-0302/

于 2009-01-18T12:06:18.770 に答える