使用公共常量模块导致循环导入

Using common constants module leads to circular import

我想从两个不同模块的 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"

我认为这与此处解决的问题相同 。 但是我真的不明白为什么 pycircular.py 中的 from my_classes.foo import Foo 被调用了第二次。

更新:

将包 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

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

After renaming the package pycircular to pycircular_pack it worked in PyCharm. But it only works because in Pycharm the option Add content roots to to PYTHONPATH is automatically set.

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

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 作为 pycircular_pack/cli.py,那么在命令行上 运行 该脚本的正确方法是使用 python -m pycircular_pack.cli;这已经 Python 设置了我们想要的路径,其中 python pycircular_pack/cli.py 不会做正确的事情。