我在包中涉及到递归导入语句的问题。我看到了很多关于该主题的文章,但找不到有效的解决方案。我转载了一个非常小的示例来解决我的问题。
软件包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
包中实现类B
和temp
的最佳pythonic方法是什么?
答案 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_a
和as_b
的首次调用的速度。