使用 reload() 打破导入循环。
使用 reload() 打破导入循环。
可能重复:
\nPython中的循环导入\na.py\n
import b class Abstract(object): pass class Concrete(Abstract): def get_newthing(self): return b.NewThing()
\n(注意:对于a.py的任何重大重构将是困难的)\nb.py\n
import a #reload(a) class NewThing(a.Abstract): pass
\n按照当前写法,运行 \"import b, a\" 是可以的,但是运行 \"import a\" 会出现\n
AttributeError: 'module' object has no attribute 'Abstract'
\n因为Python在a.py中到达 \"import b\" 这一行时,尝试访问尚未创建的 \"a.Abstract\"。\n然而,如果我包含 reload 语句,我可以正常地执行 \"import a\",因为Python会回到a.py模块,在继续执行b.py之前创建 Abstract 类。所以它似乎是有效的(尽管在执行 reload 之前应该添加一个 hasattr 检查)。\n我一直在寻找解决这个导入循环问题的方法,但没有看到过类似的建议。在这种情况下使用 reload() 有什么潜在问题吗?
问题的原因是由于模块a.py的设计不好,强制导致了循环导入的情况。循环导入通常是需要避免的。最好的解决方法是将Concrete类(以及它所需的import b语句)拆分到一个单独的模块中,该模块可以在不产生循环依赖的情况下同时导入a.py和b.py。
然而,如果对于你的情况来说,这个重构工作太多了,你可以尝试将a.py中的import b语句从顶部移到Abstract的定义之后。这样做将修复你遇到的错误,因为它确保NewThing始终能够看到Abstract的定义。
具体做法如下:
class Abstract(object): pass import b class Concrete(Abstract): def get_newthing(self): return b.NewThing()
这是一种最小的改动,但对于这种情况应该可以解决问题。然而,如果Concrete在定义时需要访问NewThing类,那么这种方法将无法修复。
还有其他导入a.py的模块,这些模块反过来又导入b.py。所以我必须将所有这些模块都移到Abstract下面。这似乎很难维护。
将Abstract移动到一个单独的文件中似乎是一个好主意。然而,我并不是真正的a.py的所有者,所以这似乎是一个相当重大的改动(这就是为什么我更喜欢不修改a.py的解决方法)。有没有什么理由认为reload()不是一个好主意?
顺便说一下,我还建议将NewThing移动到a.py中,但是团队中的其他人希望将其保留在一个单独的模块中。
使用reload()来打破import循环的问题出现的原因是reload()函数只能在交互式提示中使用。要解决这个循环引用的问题,可以按照以下方式进行修复:
class Abstract(object): pass class Concrete(Abstract): def get_newthing(self): import b return b.NewThing()
更好的做法是重构代码,避免使用循环引用。import b语句可以在模块级别使用,只需将其放在Abstract的定义之后即可。
为什么不应该使用reload来解决这个问题呢?reload函数仅在交互式解释器中使用。在文档的第三句中写道:“如果你使用外部编辑器编辑了模块源文件,并希望在不离开Python解释器的情况下尝试新版本,这将非常有用。”有其他可以解决这个问题的方法,建议使用它们。