Python 自定义包中的循环导入和 __init__.py

Python circular import in custom package and __init__.py

我收到 ImportError: cannot import name 'Result' from partially initialized module 'libs.elastic_search_hunt' (most likely due to a circular import) 当我尝试运行 测试。 但是我在我的代码中没有看到任何循环导入。

我有一个名为 elastic_search_hunt 的包,其中包含 3 个模块:

  1. elastic_query.py
  2. elastic_query_result.py
  3. search_processor.py

我还有 __init__.py 文件,其中包含以下文本:

from libs.elastic_search_hunt.elastic_query import Query
from libs.elastic_search_hunt.search_processor import SearchProcessor
from libs.elastic_search_hunt.elastic_query_result import Result

__all__ = ['Query', 'SearchProcessor', 'Result']  # I guess it does not have any effect

elastic_query.py 只有外部导入。

elastic_query_result.py一样.

search_processor.py 有那些导入:

from . import Query
from . import Result

然后我有一个测试文件,它导入 Query class:

from libs.elastic_search_hunt import Query

当我 运行 测试时,我得到这个错误:

test_query.py:2: in <module>
    from libs.elastic_search_hunt import Query
..\src\libs\elastic_search_hunt\__init__.py:2: in <module>
    from libs.elastic_search_hunt.search_processor import SearchProcessor
..\src\libs\elastic_search_hunt\search_processor.py:4: in <module>
    from . import Result
E   ImportError: cannot import name 'Result' from partially initialized module 'libs.elastic_search_hunt' (most likely due to a circular import)

但是我的代码中哪里有循环导入? 我只能假设当我从测试中导入 Query 时,它也会从 [=83 中导入 search_processor =] 模块依次加载 Query 一次。但是错误是关于 elastic_query_result 模块中的 Result 我只看到 Result[=59= 的一个导入].

当我从 __init__.py 中删除 search_processor 时,一切正常。

我看过很多关于循环导入的issues,但是都比较明显,没有触及__init__.py。我错过了什么?

TL;DR: 将 from . import Query 替换为 from .elastic_query import Query

解释:

当您从 libs.elastic_search_hunt 模块导入某些内容时,它首先加载 __init__.py。由于每个模块首先执行 import __init__.py 也正在执行。

然后 Python 执行 __init__.py 和第二行的代码

from libs.elastic_search_hunt.search_processor import SearchProcessor

它导入 search_processor.py。由于它是第一次导入 - 必须执行文件 - 因此你在该文件中的所有导入也必须立即执行:

正如您提到的,您的文件中有以下导入:

from . import Query
from . import Result

此时您告诉 python 加载 libs.elastic_search_hunt 整个模块并从中获取 Query, Result。所以 Python 确实如此。

它尝试加载 libs/elastic_search_hunt/__init__.py 但是等等...它仍然没有完全加载。所以它必须加载它,但为了正确加载它必须首先加载 search_processor ,这需要加载 elastic_search_hunt/__init__.py ....哦,好吧,有一个循环。

因此,为了避免这种行为,您应该明确说明您希望从哪个模块加载 QueryResult,因此更改

from . import Query
from . import Result

from .elastic_query import Query
from .elastic_query_result import Result

示例:失败 示例:成功