
本文详解如何在 Python 中通过 importlib 正确导入以纯数字命名的子目录(如 220_04_070)中的模块,并解决 from common import * 在相对路径下报 ModuleNotFoundError 的根本原因,提供健壮、可复用且兼容直接运行与动态导入的解决方案。
本文详解如何在 python 中通过 importlib 正确导入以纯数字命名的子目录(如 `220_04_070`)中的模块,并解决 `from common import *` 在相对路径下报 `modulenotfounderror` 的根本原因,提供健壮、可复用且兼容直接运行与动态导入的解决方案。
在 Python 项目中,当子目录名称由纯数字或含特殊字符(如 220_04_070)构成时,无法使用常规 import 220_04_070 语法,必须借助 importlib.import_module() 动态导入。但此时若子模块(如 unicorn.py)内部仍采用 from common import * 这类隐式顶层导入,就会因 Python 解释器无法在 sys.path 中定位 common 模块而抛出 ModuleNotFoundError: No module named 'common'——因为 common.py 并非安装包或顶层模块,它仅存在于 220_04_070/ 子包内。
根本原因在于:importlib.import_module('220_04_070.unicorn') 会将 unicorn 作为 220_04_070 包的子模块加载,其 __package__ 属性被设为 '220_04_070';但 unicorn.py 内部的 from common import * 是绝对导入(尝试从 sys.path 根查找 common),而非相对于当前包的相对导入。而 from .common import * 虽可解决此问题,却破坏了 unicorn.py 的独立可执行性(即 python 220_04_070/unicorn.py 会失败,因顶层模块无父包)。
✅ 推荐方案:统一使用显式绝对导入 + 包感知路径构造
不依赖 __name__ == '__main__' 做运行模式判断(该方式脆弱且易出错),而是让 unicorn.py 始终通过 importlib 或标准 import 显式声明其依赖的完整限定名:
# 220_04_070/unicorn.py
from .common import * # ✅ 相对导入 —— 当通过 import_module 加载时有效
class unicorn:
def __init__(self):
pass
def get_data(self):
print("var:", VAR1) # 直接使用导入的变量同时,在 main.py 中确保 220_04_070 是一个合法的 Python 包:
? 必须在 220_04_070/__init__.py 中添加空文件(哪怕为空)。这是 Python 将目录识别为包的必要条件。缺少它,importlib.import_module('220_04_070.unicorn') 会失败或导致包上下文丢失。
# main.py
import importlib
import sys
from pathlib import Path
# 可选:将当前目录加入 sys.path(确保包可发现,尤其在非标准工作目录下)
sys.path.insert(0, str(Path(__file__).parent))
uc = importlib.import_module('220_04_070.unicorn')
cm = importlib.import_module('220_04_070.common')
mycorn = uc.unicorn()
mycorn.get_data()⚠️ 关键注意事项:
-
220_04_070/__init__.py不可省略,否则包结构不成立; - 若需保持
unicorn.py可直接运行(python 220_04_070/unicorn.py),可在其顶部添加包路径修复逻辑(更健壮于原答案中的importlib判断):
# 220_04_070/unicorn.py
import sys
from pathlib import Path
# 当直接运行时,手动将父目录加入 path,使 '220_04_070' 可导入
if __name__ == "__main__":
package_dir = Path(__file__).parent.parent
sys.path.insert(0, str(package_dir))
# 统一使用绝对导入(推荐)
from 220_04_070.common import *
class unicorn:
def __init__(self):
pass
def get_data(self):
print("var:", VAR1)
if __name__ == "__main__":
mycorn = unicorn()
mycorn.get_data()✅ 总结:
避免在模块内混用绝对/相对导入逻辑;优先通过 __init__.py 确立包结构,使用 from .common import * 配合 importlib.import_module('pkg.submod') 实现动态加载;如需双模式(导入+直跑),用 sys.path 动态修正比运行时 importlib.import_module 判定更清晰、可靠。此方案符合 Python 官方模块系统设计,兼容 Python 3.8+,且无需修改 Python 启动参数或环境变量。


















