为何在import_module()的package参数末尾加圆点可避免ImportError?
相对导入中package参数末尾带点与不带点的差异解析
目录结构
top_package | top_module.py | +---package1 | | module1.py | | __init__.py | \---package2 | module2.py | __init__.py
各文件代码
top_module.py
from package1.module1 import CLASS1 a = CLASS1()
package1/module1.py
from importlib import import_module class CLASS1: def __init__(self): # 此写法可行: foo = getattr( import_module(name='..module2', package='package2.'), 'CLASS2')() # 此写法触发ImportError: foo = getattr( import_module(name='..module2', package='package2'), 'CLASS2')()
package2/module2.py
class CLASS2: def __init__(self): print(f'hi from: {__name__}')
问题场景
在top_package目录下执行以下命令时:
python top_module.py
第二种写法会触发错误:ImportError: attempted relative import beyond top-level package,而第一种写法(package参数末尾带点)可正常运行。
Python官方文档关于importlib.import_module的说明(翻译)
importlib.import_module(name, package=None)
导入一个模块。name参数指定要导入的模块,可以是绝对路径或相对路径(例如pkg.mod或..mod)。如果name以相对路径指定,则必须设置package参数作为解析包名的锚点(例如import_module('..mod', 'pkg.subpkg')会导入pkg.mod)。
问题解析
核心差异:相对导入层级的校验逻辑
Python解析相对导入时,会先计算相对层级(即name开头的点的数量),再对比package参数分割后的层级数:
当
package='package2'时package被分割为['package2'],仅1层级。name='..module2'的相对层级为2,超过package的层级数,触发“超出顶级包”的导入错误——因为package2是顶级包,没有父级包可供相对导入。
当
package='package2.'时package被分割为['package2', ''],层级数变为2。- 相对层级2等于
package的层级数,不会触发错误。此时解析后的模块名为module2,由于当前运行目录(top_package)在sys.path中,Python会匹配到package2包下的module2模块。
本质原因
末尾的点改变了package参数的分割结果,让Python认为它处于一个更深的层级,从而允许更高层级的相对导入。这种写法属于利用了Python导入系统的解析特性,并不推荐——正确的写法应该是使用import_module('.module2', 'package2')来导入package2.module2,或者直接用绝对导入import_module('package2.module2')。
内容的提问来源于stack exchange,提问作者abc
相关产品推荐
相关产品推荐

