关于python:导入错误-发生了什么?

Import error - what is going on?

python导入。再一次。。。

我有这个文件结构:

1
2
3
4
5
6
[test]
    start.py (from scripts import main)
    [scripts]
        __init__.py (empty)
        main.py (from . import install)
        install.py (from scripts import main # or # from . import main)

我收到导入错误:

1
2
3
4
5
6
7
8
9
10
vic@wic:~/projects/test$ python3 start.py
Traceback (most recent call last):
  File"start.py", line 2, in <module>
    from scripts import main
  File"/home/vic/projects/test/scripts/main.py", line 1, in <module>
    from . import install
  File"/home/vic/projects/test/scripts/install.py", line 1, in <module>
    from scripts import main
ImportError: cannot import name main
vic@wic:~/projects/test$

我不明白:第一次from scripts import main工作(用"工作"这个词,我的意思是它在ImportError中没有失败),第二次同样的代码给了ImportError: cannot import name main

怎么回事?

更新:

我的问题不是关于循环进口。我被这样一个事实搞糊涂了:完全相同的代码from scripts import main第一次工作正常,第二次失败。

我想有一些我不理解的内部导入机制。

第一次语句导入模块时,第二次完全相同的代码尝试从模块导入名称。这是怎么运作的?


您创建了循环导入。你不能那样做。避免从install进口main

所发生的是,在导入模块时,在执行整个顶层之前,模块是不完整的。如果在执行过程中,它导入了另一个试图(直接或间接)再次导入原始模块的模块,则此操作将失败。原始模块尚未完成导入。

换句话说,您正在创建一个圆形图形:

1
2
3
4
start -> scripts.main -> scripts.install
              ^                |
              |                |
               ----------------

您需要重新安排您的代码,使其不需要从您的scripts包中从main导入。

了解在模块中使用导入的"最佳实践"是什么?有关如何处理此问题的一些提示。


main进口installinstall进口main

  • start.py中的from scripts import main导致
  • main.py中的from . import install导致
  • install.py中的from scripts import main——循环进口

为了解决循环导入问题,可以将maininstall组合成一个模块,或者创建两个模块都可以导入的第三个模块。


这是我用来覆盖默认行为的修补程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import sys
import builtins
import importlib

def _import(name, globals=None, locals=None, fromlist=None, level=0, __import__=__import__):
   """A hack to to make names of imported modules to be available in the parent package before
    they are fully imported. If a module is present in sys.modules event if it's not fully
    imported, it should not be a problem.
    I.e. ``from package import module1, module2`` will create variables ``package.module1`` and
    ``package.module2`` at start of the import, not when it's finished.
    This helps in some situations with circular import.
   """

    module = __import__(name, globals, locals, fromlist, level)
    for attr in fromlist or ():
        sub_module = sys.modules.get(module.__name__ + '.' + attr)
        if sub_module:  # is this a module?
            # if subpackage is already being imported, even if not finished,
            # inject its name into the parent package
            setattr(module, attr, sub_module)
    return module

builtins.__import__ = _import

下面是一个测试这个的项目:https://github.com/warvariuc/python_import_improver


这应该有效:

PY:

1
from scripts import main

脚本/main.py:

1
import install

脚本/install.py:

1
import main