解决python / django应用程序中的循环依赖关系

时间:2019-01-10 04:52:51

标签: python django python-3.x

我有一个模型,该模型调用文件解析器(以解析文件),并且该文件解析器调用模型以保存对象。当前,代码看起来像这样:

models.py

class Source(models.Model):
    ...

    def parse_file(self):
        from ingest.parser import FileParser
        ...

ingest.py

class FileParser()

    def save(self):
        from models import Source
        ...

这种“工作方式”很好,但是在初始化导入时,我第一次使用save方法时在save方法中添加了大约0.25s。有没有更好的方法来完成上述操作?

1 个答案:

答案 0 :(得分:5)

首次加载模块时,具有空名称空间的模块对象将立即放入sys.modules中。在执行模块代码时,将填充名称空间。对该模块的任何其他引用都仅在sys.modues中检索该引用,而不管其是否已完全加载。这产生了解决该问题的两种方法。

方法1

由于导入的名称未在方法外部使用,因此只需要确保在调用方法时它们就存在,而不是在首次创建时就存在。

您可以通过将有问题的导入放置在各自文件的末尾来解决导入问题。这样,无论首先加载哪个模块,都将在另一个模块尝试访问它们之前初始化其中的所有顶级名称:

models.py

class Source(models.Model):
    ...

    def parse_file(self):
        ...

from ingest.parser import FileParser

ingest.py

class FileParser()
    def save(self):
        ...

from models import Source

如果首先加载models.py,则行from ingest.parser import FileParser将触发ingest.py的加载,但仅在模块命名空间中定义Source之后。这意味着from models import Source将能够找到名称。相反的情况也是如此。

如果您知道总是先加载哪个模块,则只需将其中一个导入移动到文件末尾(文件中的一个首先加载)。

方法2

一个更简单的替代方法可能是仅导入模块,而不是尝试从模块中提取名称。这样一来,您就可以将导入内容保留在文件的顶部,因为可以使用空的模块对象来满足循环导入的要求:

models.py

from ingest import parser

class Source(models.Model):
    ...

    def parse_file(self):
        # use parser. FileParser
        ...

ingest.py

import models

class FileParser()
    def save(self):
        # use models.Source
        ...