web-dev-qa-db-ja.com

Pythonインポートをオーバーライドするにはどうすればよいですか?

私は pypreprocessor に取り組んでいます。これは、cスタイルのディレクティブを受け取るプリプロセッサであり、従来のプリプロセッサのように機能させることができました(自己消費型で、後処理コードをその場で実行します) fly)ライブラリのインポートを壊すことを除いて。

問題は、プリプロセッサがファイルを実行して処理し、一時ファイルに出力し、一時ファイルをexec()することです。インポートされたライブラリは実行されないため、少し異なる方法で処理する必要があります。ライブラリはロードされ、呼び出し元モジュールからアクセスできるようになります。

私ができる必要があるのは:インポートを中断し(インポートの途中でプリプロセッサーが実行されているため)、後処理されたコードをtempModuleとしてロードし、元のインポートをtempModuleに置き換えて、呼び出しスクリプトをだましてtempModuleが元のモジュールであると信じ込むためのインポート。

私はあらゆる場所を検索してきましたが、解決策はありません。

このスタックオーバーフローの質問は、これまでに答えを提供するのに最も近いものです。 Pythonでの名前空間のオーバーライド

これが私が持っているものです。

# Remove the bytecode file created by the first import
os.remove(moduleName + '.pyc')

# Remove the first import
del sys.modules[moduleName]

# Import the postprocessed module
tmpModule = __import__(tmpModuleName)

# Set first module's reference to point to the preprocessed module
sys.modules[moduleName] = tmpModule

moduleNameは元のモジュールの名前で、tmpModuleNameは後処理されたコードファイルの名前です。

奇妙なことに、このソリューションは、最初のモジュールが正常にロードされたかのように、完全に正常に実行されます。最後の行を削除しない限り、モジュールが見つからないというエラーが発生します。

うまくいけば、スタックオーバーフローの誰かが私よりもインポートについて多くのことを知っていると思います。

注:私はソリューションを授与します。または、これがPythonで不可能な場合のみです。これが不可能でない理由の最も詳細な説明

更新:興味のある方のために、ここに作業コードを示します。

if imp.lock_held() is True:
    del sys.modules[moduleName]
    sys.modules[tmpModuleName] = __import__(tmpModuleName)
    sys.modules[moduleName] = __import__(tmpModuleName)

'imp.lock_held'パーツは、モジュールがライブラリとしてロードされているかどうかを検出します。次の行は残りを行います。

34
Evan Plaice

これはあなたの質問に答えますか? 2番目のインポートでうまくいきます。

Mod_1.py

def test_function():
    print "Test Function -- Mod 1"

Mod_2.py

def test_function():
    print "Test Function -- Mod 2"

Test.py

#!/usr/bin/python

import sys

import Mod_1

Mod_1.test_function()

del sys.modules['Mod_1']

sys.modules['Mod_1'] = __import__('Mod_2')

import Mod_1

Mod_1.test_function()
35
Ron

異なるインポート動作を定義したり、インポートプロセスを完全に覆したりするには、インポートフックを記述する必要があります。 PEP 302 を参照してください。

例えば、

import sys

class MyImporter(object):

    def find_module(self, module_name, package_path):
        # Return a loader
        return self

    def load_module(self, module_name):
        # Return a module
        return self

sys.meta_path.append(MyImporter())

import now_you_can_import_any_name
print now_you_can_import_any_name

それは出力します:

<__main__.MyImporter object at 0x009F85F0>

したがって、基本的には新しいモジュール(任意のオブジェクトにすることができます)、この場合はそれ自体を返します。 xxxのインポート時にprocesse_xxxを返すことで、インポートの動作を変更するために使用できます。

IMO: Python はプリプロセッサを必要としません。あなたが達成していることは何でも、Python自体それ自体が非常に動的な性質により、たとえば、デバッグ例の場合、ファイルの先頭にあることで何が悪いのか

debug = 1

以降

if debug:
   print "wow"

12
Anurag Uniyal

Python 2には、探している機能を提供しているように見える imputil モジュールがありますが、python 3.十分に文書化されていませんが、標準のインポート関数を置き換える方法を示すセクションの例が含まれています。

Python 3の場合、関数とクラスを含む importlib モジュール(Python 3.1で導入))があり、あらゆる種類の方法でインポート機能を変更します。プリプロセッサをインポートシステムにフックするのに適しています。

0
sth