想象一下下面的场景。您正在编写由多个文件组成的模块。在编写代码时,最终会遇到多个文件(例如main.py和side.py)相互导入的情况,从而导致递归导入,即禁止导入。
module/
main.py
side.py您决定将main拆分为多个文件:base.py和advanced.py。前者仅包含来自main.py的基本定义,不使用side或任何其他子模块;其他希望使用main的子模块应该满足于导入该子模块。后者(advanced.py)可以自由地从side导入任何东西,但是由于side不使用advanced,所以不存在递归。这将解析递归导入。
现在,您将看到以下包结构:
module/
side.py
base.py
advanced.py将base和advanced放入子文件夹main (从而创建子模块)是有意义的,因为这至少部分保留了原始的包结构。这样我们就可以得到
module/
side.py
main/
base.py
advanced.py但是现在考虑第三个文件third.py,它最初导入了整个main
from .main import *与main的接口被前面提到的“递归修复”操作符打破了。那么,如何恢复原始接口,即如何使from .main import *从base和advanced导入所有内容?
示例
原始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):
passside现在应该导入main.base而不是main
# new side.py
from .main.base import *
class C:
pass
class D(A):
pass以下是一些不完全令人满意的解决办法/想法:
__init__.py shenaningans
在__init__.py子模块中创建main,并将以下内容放入其中(来自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所需的。
相反,将shenaningans放在all.py中
与其将上述两行代码放入__init__.py中,不如将其放入另一个文件all.py中。现在,当一个人想从main导入所有东西时,他会写
from .main.all import *这仍然与from .main import *不一样,因此每当对包进行“递归修复”重组时,就必须查找所有这些导入并重写它们(通过附加.all)。
发布于 2022-03-04 19:33:05
在许多情况下,这种方法有效。要在块中导入模块的对象,例如,如果side.py使用main.A,而main.py使用inside .c,则可以在每个模块中定义简单函数,并在每个模块中导入A或C,函数返回C或A类。
在main.py中:
def get_C():
from .side import C
return C
class A:
pass
class B(get_C()):
pass在side.py中:
def get_A():
from .main import A
return A
class C:
pass
class D(get_A()):
pass在这种情况下,循环导入错误不会发生。
https://stackoverflow.com/questions/57325119
复制相似问题