首页 > 解决方案 > 使用公共常量模块导致循环导入

问题描述

我想constants从两个不同模块的模块中导入常量,但出现以下错误:

Traceback (most recent call last):
  File "C:\Temp\tmp\pycircular\pycircular\pycircular.py", line 2, in <module>
    from my_classes.foo import Foo
  File "C:\Temp\tmp\pycircular\pycircular\my_classes\foo.py", line 1, in <module>
    from pycircular.constants import ANOTHER_CONSTANT
  File "C:\Temp\tmp\pycircular\pycircular\pycircular.py", line 2, in <module>
    from my_classes.foo import Foo
ImportError: cannot import name 'Foo' from partially initialized module 'my_classes.foo' (most likely due to a circular import) (C:\Temp\tmp\pycircular\pycircular\my_classes\foo.py)

我的项目结构如下:

  |-constants.py
  |-my_classes
  |  |-foo.py
  |  |-__init__.py
  |-pycircular.py
  |-__init__.py
# =============
#     pycircular.py
# =============

from constants import SOME_CONSTANT
from my_classes.foo import Foo


def main():
    print(SOME_CONSTANT)
    my_foo = Foo()
    my_foo.do_something()


if __name__ == "__main__":
    main()
# =============
#     foo.py
# =============

from pycircular.constants import ANOTHER_CONSTANT


class Foo:

    def do_something(self):
        print(ANOTHER_CONSTANT)
# =============
#     constants.py
# =============

ANOTHER_CONSTANT = "ANOTHER"
SOME_CONSTANT = "CONSTANT"

我认为这与此处解决的问题相同https://stackoverflow.com/a/62303448/2021763。但我真的不明白为什么from my_classes.foo import Fooinpycircular.py被称为第二次。

更新:

在将包重命名pycircular为它后,pycircular_pack它在 PyCharm 中工作。但它只起作用,因为在 Pycharm 中该选项Add content roots to to PYTHONPATH是自动设置的。

的输出sys.path['C:\\Temp\\tmp\\pycircular\\pycircular_pack', 'C:\\Temp\\tmp\\pycircular', 'C:\\Tools\\miniconda\\envs\\my_env\\python39.zip', 'C:\\Tools\\miniconda\\envs\\my_env\\DLLs', 'C:\\Tools\\miniconda\\envs\\my_env\\lib', 'C:\\Tools\\miniconda\\envs\\my_env', 'C:\\Tools\\miniconda\\envs\\my_env\\lib\\site-packages']

没有该选项,输出是['C:\\Temp\\tmp\\pycircular\\pycircular_pack', 'C:\\Tools\\miniconda\\envs\\my_env\\python39.zip', 'C:\\Tools\\miniconda\\envs\\my_env\\DLLs', 'C:\\Tools\\miniconda\\envs\\my_env\\lib', 'C:\\Tools\\miniconda\\envs\\my_env', 'C:\\Tools\\miniconda\\envs\\my_env\\lib\\site-packages']

如果没有这个选项,我只能让它与绝对导入一起使用。

# pycircular.py

from constants import SOME_CONSTANT
from my_classes.foo import Foo

...
# foo.py

from constants import ANOTHER_CONSTANT

标签: pythonimporterror

解决方案


根据评论和编辑进行详细说明:

将包 pycircular 重命名为 pycircular_pack 后,它在 PyCharm 中工作。但它之所以有效,是因为在 Pycharm 中,自动设置了将内容根添加到 PYTHONPATH 选项。

您应该确保包目录设置为内容根目录或源根目录。托管包目录的目录应设置为源根目录。

C:\Temp\tmp\pycircular  # <- source root
|- pycircular_pack  # <- not set as anything
|  |- constants.py
|  |- my_classes
|  |  |- foo.py
|  |  |- __init__.py
|  |- pycircular.py
|  |- __init__.py
|- other_file.py  # <- for illustration's sake

现在您sys.path将被设置为C:\Temp\tmp\pycircular仅包含,并且只有一种方法可以从您的模块中导入内容。

即,

  • other_file.py(包外)将能够将包用作pycircular_pack
  • pycircular_pack/*.py可以通过以下任一方式引用pycircular_pack包 中的模块
    • (例如)from .constants import ...(从当前包的相对导入),或
    • (例如)from pycircular_pack.constants import ...(绝对进口)
  • pycircular_pack/my_classes/*.py可以通过以下任一方式引用pycircular_pack包 中的模块
    • (例如)from ..constants import ...(从父包的相对导入),或
    • (例如)from pycircular_pack.constants import ...(绝对进口)

如果您的pycircular_pack包将包含一个可运行的脚本,例如 CLI as pycircular_pack/cli.py,那么在命令行上运行该脚本的正确方法是使用python -m pycircular_pack.cli; 这让 Python 像我们在这里想要的那样设置了路径,在那里python pycircular_pack/cli.py不会做正确的事情。


推荐阅读