Python3:从子模块隐式导入,避免递归导入 [英] Python3: implicit import from submodules, avoiding recursive imports

查看:0
本文介绍了Python3:从子模块隐式导入,避免递归导入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象一下以下场景。您正在编写由多个文件组成的某个模块。当您编写代码时,最终会遇到多个文件(假设main.pyside.py)相互导入的情况,从而导致递归导入,这是不可能的。

module/
  main.py
  side.py
您决定将main拆分为多个文件:base.pyadvanced.py。前者仅包含main.py中的基本定义,并且不使用side或任何其他子模块;其他希望使用main的子模块应该满足于导入此定义。后者(advanced.py)可以自由地从side导入任何内容,但由于side不使用advanced,因此不存在递归。这将解析递归导入。

现在,您只剩下以下包结构:

module/
  side.py
  base.py
  advanced.py
baseadvanced放入子文件夹main(从而创建子模块)是有意义的,因为这至少部分保留了原始的包结构。因此,我们得到

module/
  side.py
  main/
    base.py
    advanced.py

但现在考虑第三个文件third.py,它最初导入了整个main

from .main import *

main的接口被前面提到的"递归修复"操作符中断。那么,如何恢复原来的界面,即如何使from .main import *同时从baseadvanced导入所有内容?


示例

原始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

side现在应该导入main.base而不是main

# new side.py
from .main.base import *

class C:
  pass

class D(A):
  pass

以下是一些不完全令人满意的解决方案/想法:

__init__.py申宁根

main子模块中创建__init__.py,并将以下内容放入其中(来自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只是跳过它。但不加载advanced所需的类C

改为将shenaningans放入all.py

不是将上述两行代码放入__init__.py,而是将其放入另一个文件all.py。现在,当用户想要从main导入所有内容时,可以写为

from .main.all import *

这仍然与from .main import *不同,因此每当发生包的这种"递归修复"重构时,必须查找所有此类导入并重写它们(通过追加.all)。

推荐答案

在许多情况下,此方法都有效。例如,如果side.py使用main.A,main.py使用side.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

在这种情况下,不会发生循环导入错误

这篇关于Python3:从子模块隐式导入,避免递归导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆