如何通过字符串形式的模块名调用导入模块的main方法?
如何动态导入学生作业模块并调用main方法?
问题场景
我正在开发一个用于测试多名学生作业的应用,目录结构如下:
app/ students/ A/ lab1/ solution.py lab2 solution.py B/ lab1/ solution.py C/ test.py
希望在test.py中导入指定学生、指定实验的solution.py,并运行其main方法。尝试用__import__函数时,返回的是顶层的students模块,无法直接调用子模块的main方法。
当前代码:
import os def get_student_names(): return os.listdir('students') def test(name, lab): if lab not in os.listdir('/'.join(['students',name])): return f"{lab} not found" if 'solution.py' not in os.listdir('/'.join(['students',name,lab])): return "solution file not found" module = __import__('.'.join(['students',name,lab,'solution'])) # 这里无法通过module.name.lab.solution.main()调用方法 def main(): student_names = get_student_names() for student in student_names: result = test(student, "lab1")
解决方案
方法1:修正__import__的调用方式
__import__函数默认返回顶层模块(比如students),需要通过fromlist参数指定非空列表,让它返回最底层的子模块:
def test(name, lab): student_lab_dir = '/'.join(['students', name, lab]) if lab not in os.listdir('/'.join(['students', name])): return f"{lab} not found" if 'solution.py' not in os.listdir(student_lab_dir): return "solution file not found" # 使用fromlist参数获取最底层的solution模块 module_path = '.'.join(['students', name, lab, 'solution']) module = __import__(module_path, fromlist=['']) # 直接调用main方法 module.main()
方法2:使用importlib.import_module(推荐)
Python 3.1+提供的importlib.import_module比__import__更直观,会直接返回目标模块:
import os import importlib def get_student_names(): return os.listdir('students') def test(name, lab): student_lab_dir = os.path.join('students', name, lab) if not os.path.isdir(student_lab_dir): return f"{lab} not found" solution_file = os.path.join(student_lab_dir, 'solution.py') if not os.path.isfile(solution_file): return "solution file not found" # 构造模块路径并导入 module_path = '.'.join(['students', name, lab, 'solution']) module = importlib.import_module(module_path) # 调用main方法 module.main() def main(): student_names = get_student_names() for student in student_names: result = test(student, "lab1")
额外注意事项
为确保Python能正确识别嵌套模块,建议在以下目录添加空的__init__.py文件:
students/students/A/、students/B/、students/C/students/A/lab1/、students/A/lab2/、students/B/lab1/
(Python 3.3+支持命名空间包,无需__init__.py也能工作,但添加后兼容性更好)
内容的提问来源于stack exchange,提问作者Artem K
相关产品推荐
相关产品推荐

