Разрешение циклических зависимостей в приложении python / django

У меня есть модель, которая вызывает анализатор файлов (для анализа файла), и этот анализатор файлов вызывает модель для сохранения объекта. В настоящее время код выглядит примерно так:

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
        ...

Это «работает» нормально, однако выполнение импорта в методе сохранения добавляет информацию о 0.25s в первый раз, когда мне приходится его использовать, поскольку он инициализирует импорт. Есть ли лучший способ сделать это?

почему бы не импортировать в начало файла, а не внутри метода

Vaibhav Vishal 10.01.2019 06:07

@VaibhavVishal, иначе это дало бы мне циклическую ошибку импорта.

David542 10.01.2019 06:07

Вы пробовали использовать функцию get_model, где можно получить модель по строковому имени?

Sergey Pugach 10.01.2019 06:14

Какое решение вы предпочли из любопытства?

Mad Physicist 10.01.2019 06:24

@MadPhysicist Я использовал подход «положить внизу», который вы предложили ниже. Однако существует ли стандартная практика, как это сделать? Например, должны ли вы включать вверху прокомментированный импорт, который говорит что-то вроде «Фактический импорт внизу файла для разрешения циклических зависимостей», или как ваши файлы обычно выглядят так, что его реализуют?

David542 11.01.2019 06:40
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
7
5
398
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Когда модуль загружается впервые, объект модуля с пустым пространством имен немедленно помещается в 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
        ...

отличный ответ. Большое спасибо за вашу внимательность.

David542 10.01.2019 06:23

Пожалуйста. Я сталкивался с этой проблемой достаточно раз, когда мог поклясться, что ваш вопрос был дубликатом, но я не могу найти достаточно точное совпадение.

Mad Physicist 10.01.2019 06:25

Другие вопросы по теме