使用reload()来打破导入循环

时间:2012-12-15 01:57:03

标签: python

  

可能重复:
  Circular (or cyclic) imports in Python

a.py

import b

class Abstract(object):
    pass

class Concrete(Abstract):
    def get_newthing(self):
        return b.NewThing()

(注意:我很难对a.py进行任何重大的重构)

b.py

import a
#reload(a)

class NewThing(a.Abstract):
    pass

如上所述,运行“import b,a”有效,但运行“import a”会给出

AttributeError: 'module' object has no attribute 'Abstract' 

当Python到达a.py中的“import b”行,然后导入b时尝试访问尚未创建的“a.Abstract”。

如果我包含reload语句,我可以“导入”就好了,因为Python跳转到a.py模块并在继续b.py之前创建Abstract类。所以它似乎工作(虽然我应该在重新加载之前添加一个hasattr检查)。

我一直在寻找解决此导入循环问题的方法,并且没有看到任何建议。以这种方式使用reload()是否有任何陷阱?

2 个答案:

答案 0 :(得分:0)

此处不要使用reload,它仅用于交互式提示。您可以像这样修复此循环:

class Abstract(object):
    pass

class Concrete(Abstract):
    def get_newthing(self):
        import b
        return b.NewThing()

更好的方法是重构代码,这样就不需要循环导入了。

答案 1 :(得分:0)

a.py模块的设计非常糟糕。它会强制您进行循环导入,这通常是需要避免的。最好的解决方案是将Concrete类(以及它所需的import b行)拆分为一个单独的模块,该模块可以导入ab,而不需要任何循环

但是,如果对您的情况进行过多的重构,您可以尝试将import b行从a.py的顶部移动到低于Abstract定义的点。这样可以解决您遇到的错误,因为它可以确保NewThing始终能够看到Abstract的定义。

即,做:

class Abstract(object):
    pass

import b

class Concrete(Abstract):
    def get_newthing(self):
        return b.NewThing()

这是一个微小的变化,但它应该适用于这种情况。如果Concrete需要对NewThing类进行定义时访问,则无法通过这种方式进行修复。