想象一下以下场景。您正在编写一些由多个文件组成的模块。当您编写代码时,最终您会遇到多个文件(比方说main.py
and side.py
) 互相导入,导致递归导入,这是不行的。
module/
main.py
side.py
你决定分手main
分成多个文件:base.py
and advanced.py
。前者仅包含基本定义main.py
并且不利用side
也没有任何其他子模块;希望使用的其他子模块main
导入这个应该感到满意。后者 (advanced.py
)可以自由地导入任何东西side
, 但是由于side
不利用advanced
,不存在递归。这解决了递归导入问题。
现在,您剩下以下包结构:
module/
side.py
base.py
advanced.py
这是有道理的base
and advanced
进入子文件夹main
(从而创建一个子模块),因为这至少部分保留了原始的包结构。这样我们就得到
module/
side.py
main/
base.py
advanced.py
但现在考虑第三个文件third.py
,最初导入了整个main
:
from .main import *
接口为main
被前面提到的“递归修复”运算符破坏了。那么,如何恢复原来的界面,也就是如何制作from .main import *
从两者导入所有内容base
and advanced
?
Example
原来的main.py
:
from .side import *
class A:
pass
class B(C):
pass
原来的side.py
:
from .main import *
class C:
pass
class D(A):
pass
重组后,main
分为两个文件:
# base.py
class A:
pass
# advanced.py
from module.side import *
class B(C):
pass
And side
现在应该正在导入main.base
代替main
:
# new side.py
from .main.base import *
class C:
pass
class D(A):
pass
以下是一些不完全令人满意的解决方案/想法:
__init__.py
恶作剧
Create __init__.py
in the main
子模块,并将以下内容放入其中(解决方案来自从子模块隐式导入 https://stackoverflow.com/questions/11325867/implicit-import-from-submodules):
from .base import *
from .advanced import *
这样做的问题是再次引入了递归导入:回想一下side
利用main.base
,因此某处有一行代码
from .main.base import *
这将调用__init__.py
,导致side
导入自advanced
以及。我们想避免这种情况。更具体地说,将以下内容放入 python 解释器中
from module.side import *
输出以下错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../module/side.py", line 2, in <module>
from .main.base import *
File ".../module/main/__init__.py", line 2, in <module>
from .advanced import *
File ".../module/main/advanced.py", line 4, in <module>
class B(C):
NameError: name 'C' is not defined
原因是,加载时advanced
,它尝试加载side
。但是由于side
是“已经加载”(或者更确切地说当前正在加载),为了避免无限递归,python 只是跳过它。但接下来上课C
,这是由advanced
,未加载。
而是把恶作剧放进去all.py
而不是将上述两行代码放入__init__.py
,将其放入另一个文件中all.py
。现在,当一个人想要从以下位置导入所有内容时main
,有人写道
from .main.all import *
这仍然不一样from .main import *
,因此每当发生这种“递归修复”包重组时,就必须查找所有此类导入并重写它们(通过附加.all
).