使用importlib动态导入包含相对导入的模块

7
我正在尝试找出如何以编程方式执行包含相对导入的模块。
伪代码:
spec = importlib.util.spec_from_file_location(name, path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)

其中name是类名,path是.py文件的绝对路径。

当被加载的模块包含相对导入时,调用exec_module会抛出以下异常:

尝试使用未知父包进行相对导入

有没有办法以编程方式执行一个包含相对导入的Python模块?如果有,怎么做呢?

2个回答

6

您的代码对我来说没有问题。

可能存在的一个问题是您使用的name的值。为了使相对导入正常工作,您需要完全指定模块名称(例如name = "package1.package2.mymodule")。

例如:

runimport.py

import importlib
import os

name = "testpack.inside" # NOT "inside"

spec = importlib.util.spec_from_file_location(name, 
    os.path.join(os.path.dirname(__file__), 'testpack/inside.py'))
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)

testpack/init.py

# empty

testpack/inside.py

from . import otherinside
print('I got', otherinside.data)

testpack/otherinside.py

data = 'other inside'

现在,python3 runimport.py会输出"I got other inside"。如果你用"inside"替换名称,它会抛出你所描述的错误。

0
问题在于,10年前创建的原始PEP 451存在缺陷,并声称您的导入规范包含导入模块所需的所有数据。实际上,模块规范没有正确跟踪Python中的包结构。因此,您需要明确指定模块从包结构的哪个位置加载。
这意味着您需要在某些加载调用中添加mypackage.subpack2.subpackge2.hairy3.mypackage。例如,
find_spec("mypackage")

是不正确的,你需要使用

find_spec("mypackage.subpack2.subpackge2.hairy3.mypackage")

正确加载模块的方法是: 在您的情况下,您需要找到包的根目录,并将其添加到调用spec_from_file_location函数的名称中。可惜的是,这个复制粘贴的解决方案太长而且复杂,无法适应这个评论框。 尝试在Python论坛上抱怨这个问题,以便得到修复。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接