为何Python中`from lib import client`有效,`import lib.client`却报模块不存在?
from lib import client可行,import lib.client却报错? 为了理解Python的导入机制,我设计了嵌套导入测试:将Framework库中的client模块导入到Domain/lib包中,再在app.py中尝试两种不同的导入方式调用其中的函数。
目录结构
Init_Package_Import Domain app app.py lib __init__.py Framework __init__.py client.py
各文件内容
Init_Package_Import/Framework/init.py
# Init_Package_Import/Framework/__init__.py
Init_Package_Import/Framework/client.py
# Init_Package_Import/Framework/client.py: def hi_client(): print("Hi Client")
Init_Package_Import/Domain/lib/init.py
# Init_Package_Import/Domain/lib/__init__.py: import sys sys.path.insert(0, 'Init_Package_Import') from Framework import client as client
Init_Package_Import/Domain/app/app.py
# Init_Package_Import/Domain/app/app.py: import sys sys.path.insert(0, 'Init_Package_Import/Domain') # 导入方式1 - 正常运行 from lib import client as client1 # 导入方式2 - 抛出错误 import lib.client as client2
问题
执行命令python3 Init_Package_Import/Domain/app/app.py时,出现ModuleNotFoundError: No module named 'lib.client'错误。为什么第一种导入方式有效,第二种却不行?
原因解析
这两种导入方式的逻辑完全不一样:
from lib import client的工作逻辑
执行这条语句时,Python先通过你添加的sys.path找到lib包,然后执行lib/__init__.py里的代码——你在这个文件里已经把Framework.client模块导入进来,并重命名为client放到了lib包的命名空间里。所以from lib import client其实是直接从lib包的命名空间中取出这个已经存在的client对象,不需要额外查找其他模块文件。import lib.client的工作逻辑
这条语句的核心是寻找lib包下的子模块client,也就是要求项目中必须存在lib/client.py文件或者lib/client目录(包含__init__.py)。但你的项目里根本没有对应的文件或目录结构,Python找不到符合要求的子模块,自然就抛出了找不到模块的错误。
简单来说,lib包里的client只是一个导入到命名空间的别名,不是真正的子模块文件,所以只能用from...import的方式从包的命名空间中获取,而不能用import lib.client这种寻找子模块的语法。
内容的提问来源于stack exchange,提问作者jhan2

