#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