2011-02-05 11 views
3

pythonソースファイルのパスを解析し、それぞれのファイルとDoStuff ™をインポートされた各モジュールにインポートしようとしています。各.pyファイルをパスに読み込む - imp.load_moduleは相対インポートについて文句を言います

def ParsePath(path): 
    for root, dirs, files in os.walk(path): 
     for source in (s for s in files if s.endswith(".py")): 
      name = os.path.splitext(os.path.basename(source))[0] 
      m = imp.load_module(name, *imp.find_module(name, [root])) 
      DoStuff(m) 

上記のコードは動作しますが、パッケージが認識されないValueError: Attempted relative import in non-package

私の質問は、私は与えられたモジュールがパッケージの一部であることをimp.load_moduleを教えてくださいどのように、基本的にはありますか?

+0

あなたはどのようなディレクトリ構造を持っていますか?関数に渡す 'path'はパッケージのルートパスですか? – shang

+0

この質問の目的の一部は、パスに関係なく、パッケージを手動で作成する方法を理解することです。確かに、ParsePathを迂回させて、常にコンテンツの前に '__init __。py'を含むディレクトリをインポートしようとしました。私はそれがうまくいくと思っていますが、それはIMHOの問題を解決する正しい方法ではありません。 – porgarmingduod

答えて

3

あなたは直接輸入プロトコルメソッド与えられたモジュールがパッケージの一部であることをload_moduleを伝えることはできません。 PEP 302 New Import Hooks

から撮影内蔵の__import__機能(import.cにPyImport_ImportModuleEx として知られている) その後、 インポートを実行するモジュールは、パッケージまたはパッケージのサブモジュールであるかどうかを確認します。実際に (aのサブモジュール)パッケージの場合は、最初にパッケージ(サブモジュールの親パッケージ)に対して相対的なインポート を実行しようとします。たとえば、 というパッケージに「spam」という名前のパッケージが「eggをインポートする」場合、最初に という名前のモジュールが「spam.eggs」で検索されます。それが失敗すると、インポートは 絶対インポートとして続き、「eggs」という名前のモジュールが検索されます。点線 名前のインポートはほぼ同じです:パッケージ "spam"が "import eggs.bacon"(そして "spam.eggs"があり、それ自体が パッケージです)の場合、 "spam.eggs.bacon"が試されます。それが失敗した場合、 "eggs.bacon"は が試行されます。 (これらは輸入 プロトコルの実装とは関係ありません あり、ここで説明されていない多くの機微がありますが、。)メカニズムでダウン

深く、点線の名前のインポートは そのコンポーネントによって分割されます。 "import spam.ham"の場合、まず "import spam"は であり、成功した場合には "ham"がサブモジュール "spam"としてインポートされます。

輸入者プロトコルは、このレベルの の輸入で動作します。インポータが 「spam.ham」のリクエストを取得するまでには、 モジュール「spam」が既にインポートされています。

次に、サブモジュールをロードする前に、組み込みのインポートが行うことをシミュレートし、親パッケージをロードする必要があります。

+0

私は、モジュール、パッケージ、およびインポートするものはPythonの唯一の部分だと思います。数日前に私はすでにハックなソリューションを作っていましたが、これをクリアしたことに感謝します。あなたはそれをすることはできませんが、満足していない場合は、少なくとも役に立つかもしれません。 – porgarmingduod

2

機能imp.find_moduleは常にドットなしのプレーンモジュール名を取りますが、imp.load_moduleのドキュメントは

を言い、これはパッケージのサブモジュールである場合、名前の引数は、(パッケージ名を含む完全なモジュール名を示し、 )。

だから、あなたはこれを試みることができる:

def ParsePath(path): 
    for root, dirs, files in os.walk(path): 
     for source in (s for s in files if s.endswith(".py")): 
      name = os.path.splitext(os.path.basename(source))[0] 
      full_name = os.path.splitext(source)[0].replace(os.path.sep, '.') 
      m = imp.load_module(full_name, *imp.find_module(name, [root])) 
      DoStuff(m) 
+0

あなたは正しいアイディアを持っています(あなたが投稿したコードのいくつかのエラーと、それが絶対にうまくいかないという事実を除けば)が、実際には役に立たない。あなたの最初のコメントに答えて説明したように、私はサルのパッチを探していません。私は自分の猿のパッチを作ることができます。私は**答え**を探していますが、これはそれではありません。 – porgarmingduod

+0

さて、私はあなたの質問を正しく理解していません。モジュールがパッケージの一部であることを 'imp.load_module'に知らせる方法を探していて、パッケージ名を含む完全修飾名(つまりドット付き)を与える方法があります。 – shang

0

私は同じ問題を抱えていました。良いニュースは、それを行う方法があることですが、のインプットのimportlibの組み合わせを使用する必要があります。ここでは説明のための例です:

import imp 
import importlib 
package_path = r"C:\path_to_package" 

package_name = "module" 
module_absolute_name = "module.sub_module" 
module_relative_name = ".sub_module" 

# Load the package first 
package_info = imp.find_module(package_name, [package_path]) 
package_module = imp.load_module(package_name, *package_info) 

# Try an absolute import 
importlib.import_module(module_absolute_name, package_name) 

# Try a relative import 
importlib.import_module(module_relative_name, package_name) 

我々はすでに親パッケージをロードしたとサブモジュールは、それがに対するインポートされているものを知っているのimportlibによって正しくロードされているので、これはsub_moduleが相対モジュールパスを使用してインポートすることができます。

私はこの解決策がPython 2. *で固まっている人にとって必要であると確信していますが、それを確認する誰かが必要です。

関連する問題