2

PYTHONPATH にパッチを適用して現在のディレクトリを追加するデコレーターを使用して、初期化モジュール内に関数呼び出しをラップします。これにより、パッケージを PYTHONPATH に明示的に追加することを心配することなく、モジュール内で相対インポートを使用できます (@abarnert のコメントに基づいて編集)。

def patch_python_path(f):
    @wraps(f)       
    def wrap(*args, **kwargs):
        ROOT = os.pathsep.join([os.path.abspath(os.path.dirname(__file__))])
        if not os.environ.has_key("PYTHONPATH"):
            os.environ["PYTHONPATH"] = ""
        if not (ROOT in os.environ["PYTHONPATH"].split(":")):
            os.environ["PYTHONPATH"] = "%s:%s" % (os.environ["PYTHONPATH"], ROOT)
        if not ROOT in sys.path:
            sys.path.append(ROOT)
        return f(*args, **kwargs)
    return wrap

使用方法は次のとおりです。

@patch_python_path
def initialize():
    #at this point any code being run has access to local modules through relative imports
    pass

このアプローチには、私が気付いていない大きな問題はありますか?


これに関する私の目的は次のとおりです。

  • ユーザーが追加の環境操作なしですぐに使用できる自己完結型のブートストラップが必要です
  • また、ユーザーがブートストラップ パッケージの名前を変更できると想定しているため、すべてのインポートが相対的なままであることが不可欠です。

[編集] 私が直面している問題は、純粋な Python モジュールのインポートとは対照的に、Fabric がタスクを実行する方法に関係していることを実際に認識しています。(fab task1 とは対照的に) Python シェルからタスクを実行しようとすると、パッチを適用する必要なく、すべてのインポートが正しく解決されます。fab を介してタスクを実行するとインポート エラーが発生する

4

2 に答える 2

2
  1. os.environグローバルです。あなたはそれを修正しているのであって、後でそれを修正しているのではありません。したがって、@patch_python_path任意の関数を実行した後、他のモジュールやトップレベルのスクリプトを含め、その後に定義する他のすべてと同等の処理を実行しました。
  2. sys.pathもグローバルであり、これも変更していて、復元していません。
  3. PYTHONPATHとの両方を変更する必要はありませんsys.path。(特に、通常は必要ないのは前者です。)
  4. に追加していますが、に追加.していPYTHONPATHます。両方を変更する必要がある場合は、の後にすべてが機能しなくなります。これにより、は効果的に変更されますが、は変更されません。os.getcwd()sys.pathos.chdir()PYTHONPATHsys.path
  5. ラップされた関数は、そのdocstring、nameなどを失います。関数で使用@functools.wrapsしますwrap

これらはすべて、そもそもそれが良い考えであるかどうかに関係なく、実装に関する単なる問題です。

人々がこのようなものを望む最も一般的な理由は、(a)PythonXYパッケージをPythonVWのように機能させること、および(b)ソースツリーからのパッケージのインポートを、インタープリターシェルからでもインストール後にインポートするのと同じように機能させることです。前者はおそらく悪い考えです。後者は便利ですが、それを達成する他の方法があります。いくつかの異なるより高いレベルの目標がある場合、これがそれを達成するための最良の方法であるかどうかを誰かがあなたに言うことができる前に、あなたはその目標が何であるかを私たちに言わなければなりません。

于 2012-11-13T01:22:35.653 に答える
1

現在のパスをsys.path次の場所に追加するだけです。

import sys
def patch_python_path(f):
    def wrap(*args, **kwargs):
        if not '.' in sys.path:
            sys.path.append('.')
        return f(*args, **kwargs)

    return wrap
于 2012-11-13T01:18:19.223 に答える