使用 importlib.import_module 时出现 ModuleNotFoundError

dcu*_*dcu 5 python python-import python-3.x

我有以下文件夹结构,并且在 util.py 中有一个测试方法。运行 util 方法时,我看到一个模块出错,该模块导入到我试图获取所有类的模块中。

Parent
--report <dir>
----__init__.py
----AReport.py
----names_list.py
--util.py
Run Code Online (Sandbox Code Playgroud)

实用程序

import inspect
import importlib
import importlib.util

def get_class_names(fileName):
    for name, cls in inspect.getmembers(importlib.import_module(fileName, package='report'), inspect.isclass):
        print(name, cls)

if __name__ == '__main__':
    get_class_names('report.names_list')

Run Code Online (Sandbox Code Playgroud)

名称列表.py

from AReport import AReport

class Team:
    name = ""
    def __init__(self, name):
        self.name = name

class Names_List(AReport):
    def __init__(self, name=None):
        AReport.__init__(self, name)

    def test(self):
        print('In test')        
Run Code Online (Sandbox Code Playgroud)

报表文件

from abc import ABCMeta, abstractmethod

class AReport(metaclass=ABCMeta):
    def __init__(self, name=None):
        if name:
            self.name = name

    def test(self):
        pass

Run Code Online (Sandbox Code Playgroud)

当我从 util 运行我的测试方法时,出现以下错误:

ModuleNotFoundError: No module named AReport
Run Code Online (Sandbox Code Playgroud)

Gin*_*pin 8

假设您没有使用sys.path或更改任何内容PYTHONPATH,问题是AReport模块在 util.py 中不“可见”。

您可以通过在顶部添加以下内容来检查util.py

import sys
print(sys.path)
Run Code Online (Sandbox Code Playgroud)

这将打印出解释器将在其中查找模块的所有路径的列表。你会看到只有Parent模块的路径在那里,因为这是util.py运行的地方。这在模块搜索路径文档中进行了解释:

spam导入命名的模块时,解释器首先搜索具有该名称的内置模块。如果未找到,它将搜索spam.py在变量给出的目录列表中命名的文件sys.pathsys.path从这些位置初始化:

  • 包含输入脚本的目录(或未指定文件时的当前目录)。
  • PYTHONPATH(目录名称列表,语法与 shell 变量相同PATH)。
  • 依赖于安装的默认值。

当您util.py从父目录(=“包含输入脚本的目录”)运行时,您执行

from AReport import AReport
Run Code Online (Sandbox Code Playgroud)

它将AReport从 Parent 目录中寻找一个模块,但它不在那里,因为只有report包直接在 /path/to/Parent 目录下。这就是为什么 Python 将ModuleNotFoundError. 如果你这样做

from report.AReport import AReport
Run Code Online (Sandbox Code Playgroud)

它会起作用,因为report包在 /path/to/Parent 下。

如果您想report.在导入时避免使用前缀,一种选择是将report包添加到sys.pathon util.py

import sys
sys.path.append("./report")

print(sys.path)
# should now show the /path/to/Parent/report on the list
Run Code Online (Sandbox Code Playgroud)

然后您的from AReport导入现在将起作用。另一种选择是PYTHONPATH在运行之前将 /path/to/Parent/report 添加到您的环境变量中util.py

export PYTHONPATH=$PYTHONPATH:/path/to/Parent/report
Run Code Online (Sandbox Code Playgroud)

我通常使用PYTHONPATH测试选项,这样我就不需要修改代码。