Python3.3支持隐式打包,为何子目录未被识别为子包?
问题原因分析
你碰到的报错和有没有__init__.py、是否支持隐式打包完全无关,核心是绝对导入的路径规则和模块搜索路径不匹配:
- Python 3.3+的隐式打包(PEP 420 命名空间包)仅取消了「目录必须包含
__init__.py才能被识别为包」的限制,没有修改导入的基本规则:所有绝对导入都会从sys.path(Python的模块搜索路径列表)下的路径开始匹配查找。 - 运行
outside_main.py时,Python会自动把outside_main.py所在的outer_dir目录加入sys.path,这时候导入package_example.module_main能成功,是因为outer_dir下确实存在package_example这个包目录。但module_main.py里写的from level_1.foo_1 import xxx属于绝对导入,Python会直接去sys.path下找名为level_1的包,而sys.path里只有outer_dir,outer_dir下并没有level_1(它存放在package_example目录下),自然就会抛出ModuleNotFoundError。
补充:你的报错日志里出现的
module_example属于笔误,正常目录名为package_example的话,outside_main.py的导入应该为from package_example.module_main import main。
加
__init__.py能不能解决问题? 不能。就算给所有目录都加上__init__.py,只要导入路径的写法不变,Python还是会去sys.path根路径下查找level_1,报错会完全相同。
正确的解决方案
有两种常用的修复方式:
方式1:使用包内相对导入
修改module_main.py里的导入语句,用.表示当前模块所在的包目录:
# module_main.py 修复后 from .level_1.foo_1 import foo_function_1 from .level_1.level_2.foo_2 import foo_function_2 def main(): print(foo_function_1()) print(foo_function_2()) if __name__ == "__main__": main()
注意:使用相对导入后,不能直接运行
python module_main.py当做独立脚本执行,只能作为包的一部分被外部导入,或者用python -m package_example.module_main的方式运行。
方式2:写全绝对导入的完整包路径
修改module_main.py里的导入语句,从根包package_example开始写全路径:
# module_main.py 修复后 from package_example.level_1.foo_1 import foo_function_1 from package_example.level_1.level_2.foo_2 import foo_function_2 def main(): print(foo_function_1()) print(foo_function_2()) if __name__ == "__main__": main()
这种写法下,只要package_example所在的outer_dir在sys.path中,不管是被outside_main.py导入,还是用python -m package_example.module_main运行都可以正常执行。
内容的提问来源于stack exchange,提问作者CSStudent7782
相关产品推荐
相关产品推荐

