在路径中加载每个.py文件 - imp.load_module会抱怨相对导入

时间:2011-02-05 13:18:05

标签: python import

我正在尝试解析python源文件的给定路径,将每个文件和DoStuff™导入到每个导入的模块中。

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某个模块是否属于某个包?

3 个答案:

答案 0 :(得分:3)

您不能直接告诉导入器协议方法load_module所提供的模块是包的一部分。取自PEP 302 New Import Hooks

  

内置__import__功能   (称为PyImport_ImportModuleEx       在import.c)然后将检查模块是否正在执行       import是包的包或子模块。如果它确实是一个       (子模块的一个)包,它首先尝试做相关的导入       到包(子模块的父包)。例如,如果       一个名为“垃圾邮件”的软件包会“导入鸡蛋”,它会首先查找   一个       模块名为“spam.eggs”。如果失败,导入继续作为       绝对导入:它将寻找一个名为“eggs”的模块。带点       名称导入工作几乎相同:如果包“垃圾邮件”       “import eggs.bacon”(和“spam.eggs”存在,本身就是一个       包),“spam.eggs.bacon”尝试。如果失败“eggs.bacon”是       试过。 (这里没有描述更多细微之处,但是       这些与进口商的实施者无关   协议)。

     

在机制中更深入,虚线名称导入被拆分       它的组件。对于“import spam.ham”,首先是“导入垃圾邮件”       完成,只有当成功导入“ham”作为子模块导入时       “垃圾邮件”。

     

导入器协议在个人的此级别运行      进口。当进口商收到请求时   “spam.ham”       模块“垃圾邮件”已经导入。

然后,您必须模拟内置导入的功能,并在加载子模块之前加载父包。

答案 1 :(得分:2)

函数imp.find_module总是采用没有点的普通模块名称,但imp.load_module的文档说

  

name参数表示完整的模块名称(包括包名称,如果这是包的子模块)。

所以你可以试试这个:

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)

答案 2 :(得分:0)

我遇到了同样的问题。好消息是有一种方法可以做到这一点,但你必须使用 imp 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)

这将允许使用相对模块路径导入 sub_module ,因为我们已经加载了父包,并且importlib正确加载了子模块以了解它被导入的内容相对于。

我相信这个解决方案只适用于我们这些陷入Python 2. *的人,但需要有人确认。