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

Dav*_*542 7 python django python-3.x

我有一个模型调用文件解析器(解析文件),文件解析器调用模型来保存对象.目前,代码看起来像这样:

models.py

class Source(models.Model):
    ...

    def parse_file(self):
        from ingest.parser import FileParser
        ...
Run Code Online (Sandbox Code Playgroud)

ingest.py

class FileParser()

    def save(self):
        from models import Source
        ...
Run Code Online (Sandbox Code Playgroud)

这个'工作'很好,但是,在save方法中进行导入会增加0.25s我第一次使用它时,因为它正在初始化导入.有没有更好的方法来做到这一点?

Mad*_*ist 5

首次加载模块时,会立即将具有空命名空间的模块对象放入sys.modules.在执行模块代码时填充命名空间.对模块的任何进一步引用只是检索引用sys.modues,无论它是否完全加载.这产生了两种解决问题的方法.

方法1

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

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

models.py

class Source(models.Model):
    ...

    def parse_file(self):
        ...

from ingest.parser import FileParser
Run Code Online (Sandbox Code Playgroud)

ingest.py

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

from models import Source
Run Code Online (Sandbox Code Playgroud)

如果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
        ...
Run Code Online (Sandbox Code Playgroud)

ingest.py

import models

class FileParser()
    def save(self):
        # use models.Source
        ...
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案.非常感谢你的彻底性. (2认同)