导入错误。循环引用

Posted

技术标签:

【中文标题】导入错误。循环引用【英文标题】:Import Error. Circular References 【发布时间】:2012-06-17 05:27:14 【问题描述】:

我有一个这样的包

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleA.py
        moduleB.py
        moduleC.py
        moduleD.py
    subpackage2/
       __init__.py
       moduleX.py
       moduleY.py
       moduleZ.py

在moduleB.py中,我正在导入

from moduleA import bar

在moduleA中,我正在导入

from moduleB import foo

我收到 ImportError。

ImportError: cannot import name foo

这可能是什么问题?为了避免这个问题,我该怎么办?我应该在 _init_.py pf package, subpackage1, subpackage2 中写什么?

_init_子包1的.py

from moduleA import *
from moduleB import *
from moudleC import *
from moudleD import *

_init_子包2的.py

from moduleX import *
from moduleY import *
from moduleZ import *

_init_包的.py

from subpackage1 import *
from subpackage2 import *

我的 _init_.py 文件有问题吗?

编辑: 我改变了进口

模块B

from .moduleA import bar

模块A

from .moduleB import foo

不过,我还是遇到了同样的导入错误。

ImportError: cannot import name foo

编辑

模块B

def Bar():
    def __init__(self):
        self.foo = Foo()
        self.val = 10
        .
        .

模块A

def Foo():
    def __init__(self):
        self.bar = Bar()
        self.val = 5
        .
        .   

我想这样做。而且我坚持将这两个类保存在不同的文件中。我应该如何导入?

【问题讨论】:

我想你的意思是 Foo 类和 Bar 类?无论哪种方式,我都会在我的回答中展示一些如何做到这一点的例子。 ModuleB 或 ModuleA 中只有一个必须遵循我展示的模式之一,另一个仍然可以在顶部执行。还有其他问题吗? 谢谢。它正在工作。但我得到了 RuntimeError: maximum recursion depth exceeded。我从 Foo 的 Bar 和 Bar 给 Foo 打电话。我会调查的。 不客气。听起来您在那里进行了一些无限递归,如果您在每次初始化它们时都创建另一个新的递归,这是可以预料的。你需要重新考虑你的设计。也许你可以在实例化 Bar() 时从 Foo() 中传入一个引用。这样,bar 就有了 foo。例如。在 Bar: (__init__(self, foo): self.foo = foo) 和在 Foo: (__init__(self): self.bar = Bar(self)) 【参考方案1】:

这实际上似乎是循环导入的问题。

你的模块B说“从模块A导入栏”,它试图加载模块A,但它在模块A中遇到的第一件事是“从模块B导入foo”,它将它发送回模块B。所以你有一个无法解决的循环递归。

通常(但并非总是)循环导入表明您需要重新考虑或重新构建您的工作方式。但是,有一些可能的解决方法。

一种是将 import 语句移动到 python 文件的底部(假设您在另一个函数中使用 foo 或 bar,因此在文件加载时不会立即调用它)

例如

#ModuleB.py 
class Bar(object):   
  def __init__(self):
    self.foo = Foo()
    self.val = 10
    .
    .
# at bottom of file
from moduleA import Foo

另一种选择是将导入语句放在一个函数中,称为“惰性导入”模式:

#ModuleB.py 
class Bar(object):   
  def __init__(self):
    from moduleA import Foo
    self.foo = Foo()
    self.val = 10

关于您对__init__.py 文件的问题。我看不出你为什么不把它们留空。空的__init__.py 文件只是告诉 python“这个目录是一个 python 包”并允许导入。

通常,您的包目录中有一个文件,该文件通过导入和利用子包中的模块来“运行”您的程序。因此,假设存在这样的文件(例如 package/main.py),您的导入将如下所示,只有空的 __init__.py 文件。

#package/main.py
from subpackage1.moduleA import bar  # you can now call bar() directly
from subpackage1 import moduleB  # you can now call foo like: moduleB.foo()
from subpackage2.moduleX import jah 

您在上面所做的基本上是获取每个子包中所有模块的所有功能和属性,并使它们直接在子包上可用,就好像它们是子包的功能和属性一样(所以你可以import subpackage1 和调用subpackage1.bar()subpackage.foo() 而不是subpackage.moduleA.bar() 等),但我不认为这就是你想要做的事情,必然,在这种情况下可能没有理由这样做。

如果您需要在 subpackage1 的模块中使用 subpackage2 中的某些内容,请参阅this question. 的答案或 google 如何将目录添加到您的 python 路径。

【讨论】:

【参考方案2】:

这与层次结构无关,它与循环引用有关。您不能告诉文件 A 导入文件 B,并告诉文件 B 导入文件 A - 因为它们相互依赖,所以无法解析循环。

要么重组你的文件,使它们不需要相互导入——记住 Python 不是 Java,你可以在一个文件中拥有多个类——或者将其中一个导入移动到一个函数中,这样它就不需要'不必在导入时执行。

【讨论】:

以上是关于导入错误。循环引用的主要内容,如果未能解决你的问题,请参考以下文章

检测到实体框架自引用循环

为啥iOS的Masonry中的self不会循环引用

错误错误 522:循环引用

Dagger 2 - 为啥我收到循环引用错误?

由于循环依赖错误,无法添加对项目的引用

怎么取消循环引用警告