递归导入语句

时间:2019-04-17 19:45:57

标签: python python-import

我在包中涉及到递归导入语句的问题。我看到了很多关于该主题的文章,但找不到有效的解决方案。我转载了一个非常小的示例来解决我的问题。

软件包temp中的文件组织如下:

|-- __init__.py
|-- abstract.py
|-- a.py
|-- b.py

文件__init__.py包含

from .a import A
from .b import B

文件abstract.py包含

from abc import ABC, abstractmethod

class Abstract(ABC):

    @abstractmethod
    def __init__(self):
        pass

文件a.py包含

from .abstract import Abstract
from .b import B

class A(Abstract):

    def __init__(self, string):
        super().__init__()
        self.string = string

    def as_b(self):
        return B(int(self.string))

文件b.py包含

from .abstract import Abstract
from .a import A

class B(Abstract):

    def __init__(self, integer):
        super().__init__()
        self.integer = integer

    def as_a(self):
        return A(str(self.integer))

然后我创建了一个文件foo.py,以测试其中包含的temp

from temp import A, B

an_a = A("2")
a_b = B(4)

an_a_as_b = A.as_b()
a_b_as_a = B.as_a()

在运行时,我收到错误ImportError: cannot import name 'A'。我的理解是,这归因于递归import语句(A类导入B类,反之亦然)。

A包中实现类Btemp的最佳pythonic方法是什么?

1 个答案:

答案 0 :(得分:2)

除了合并文件以外,还有其他几种选择,您说过,您的工作场所惯例不建议使用。 (下面的选项适用于this comment from Sanyash中链接的答案的Python 3 relative。我认为在此处包括答案是有道理的,因为该问题并不直接与相对导入有关。)

将循环导入移动到文件末尾

文件a.py变为:

from .abstract import Abstract

class A(Abstract):
    # ...

from .b import B

b.py的更改方式相同。这是一个简单的更改,但缺点是您的进口分散。有人可能会通过将导入移到顶部来“清理”您的代码,并遇到同样的困惑。 (您可以发表评论,但人们经常会错过评论。)

导入模块而不是类

您还可以让每个模块导入另一个模块,而不是从另一个模块导入。 a.py变为:

from .abstract import Abstract
from . import b

class A(Abstract):
    # ...
    def as_b(self):
        return b.B(int(self.string)) # note the change to use b.B

,当然b.py也有类似的变化。这使我成为最干净的解决方案-我极力主张尽可能将进口货物保持在一起。 (我认为这种方法没有任何缺点,但是如果有人知道任何缺点,请发表评论,我会对此进行更新。)

将导入内容移至使用位置

如果仅在这样的位置引用B中的a.py,则可以将导入移动到需要的位置:

from .abstract import Abstract

class A(Abstract):
    # ...

    def as_b(self):
        from .b import B
        return B(int(self.string))

,与b.py相同。与第一个选项相比,它具有一个优势,即可以更轻松地了解为什么导入不在顶部,并且我认为它不太可能导致混乱或错误。但是,它可以掩盖导入错误,所以我认为这不是理想的选择。由于导入将在每个函数第一次被调用时发生并且花费非零时间,因此也会稍微降低对as_aas_b的首次调用的速度。