настройки python для проекта — циклический импорт / внедрение зависимостей

#python #dependency-injection #settings #python-import

#python #внедрение зависимостей #Настройки #python-импорт

Вопрос:

Я создал файлы настроек в стиле Django для разных сред. Файлы настроек определяют некоторые переменные, а также служат для внедрения зависимостей для других модулей.

Таким образом, структура:

 settings/
    ___init__.py
    base.py
    dev.py
    dev2.py
    prod.py

service/
    __init__.py
    service.py
    service_mock.py
  

И в settings/__init__.py я пишу:

 settings_env = os.environ.get('PROJECT_SETTINGS', '')
if settings_env == 'prod':
   from .prod import *
elif settings_env == 'dev':
   from .dev import *
  

Каждый файл настроек определяет различные переменные, а также импортирует класс из service.py или service_mock.py , в зависимости от переменной среды.
В основном это работает нормально.

Теперь проблема в том, что service.py не удается импортировать пакет настроек, потому что файлы настроек импортируют service.py , так что это станет циклическим импортом.

Как я вижу в Django, это решается с помощью строк импорта в файлах настроек вместо фактического импорта. Мне не очень нравится идея, поскольку я теряю некоторые функции автозаполнения IDE, также я не уверен, как на самом деле создать объект настроек, который предоставляет Django.

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

Ответ №1:

Очень распространенное и, безусловно, самое простое решение циклического импорта — отложить импорт до тех пор, пока он вам действительно не понадобится. Например, изменить

 import settings
def func():
    settings.things
  

Для

 def func():
    import settings
    settings.things
  

Если вам абсолютно необходим глобальный импорт модулей, вы могли бы использовать различные приемы, такие как

 settings = None
def import_stuff():
    global settings
    import settings as s
    settings = s
  

или иметь класс

 class Settings():
    mod = None        

    def __getattr__(self, attr):
        if self.mod is None:
            import settings
            self.mod = settings
        return getattr(self.mod, attr)

settings = Settings()
  

(или обобщите для любого имени модуля)

Комментарии:

1. Спасибо. Какой смысл в getattr if? не было бы нормально импортировать настройки при каждом доступе getattr? Считается ли это хорошим шаблоном для импорта подобным образом? есть ли лучшие шаблоны, например, использование ini-файла? На самом деле я бы предпочел ini-файл, но тогда я теряю возможности кода python

2. Нет, вы бы использовали шаблон только в том случае, если это абсолютно необходимо, а другие сочли бы это халтурным. Вы могли бы импортировать каждый раз с небольшими затратами на производительность. Я забыл сказать: лучше всего было бы, конечно, выделить то, что вам нужно импортировать в обоих местах, в отдельный модуль, который не зависит ни от того, ни от другого!

3. Можете ли вы объяснить, как? все в коде должны импортировать настройки. но настройки импортируют службу или макет службы для других модулей. Или, как я могу использовать ini / текстовый файл и при этом получать преимущества кода python (например, создавать экземпляр класса)?

4. Рефакторинг, я думаю, выходит за рамки того, что можно показать здесь, извините. Возможно, если бы вы начали другой вопрос с некоторыми особенностями вашей ситуации.

Ответ №2:

Вместо:

 settings_env = os.environ.get('PROJECT_SETTINGS', '')
if settings_env == 'prod':
   from .prod import *
elif settings_env == 'dev':
   from .dev import *
  

вы можете просто экспортировать переменную:

 DJANGO_SETTINGS_MODULE your_project.settings.dev2
  

и Django прочитает нужный файл.

Также: Вместо

 import settings
  

вы хотели бы использовать:

 from django.conf import settings
  

и выше могут быть вложены в методы / функции, чтобы избежать циклического импорта.

смотрите: https://docs.djangoproject.com/en/dev/topics/settings/#using-settings-in-python-code

смотрите: https://docs.djangoproject.com/en/dev/topics/settings/#custom-default-settings

Комментарии:

1. Мой проект не django, я пытаюсь реализовать настройки стиля django