Я всегда использовал файлы JSON для настройки своих приложений. Я начал использовать их с того времени, когда много программировал на Java, и сейчас я работаю в основном над разработкой Python на стороне сервера и наукой о данных и не уверен, что JSON - это правильный путь.
Я видел, как Celery использует реальные файлы Python для конфигурации. Первоначально я скептически относился к этому. Но идея использования простых структур данных Python для конфигурирования начинает развиваться. Некоторые плюсы:
- Структуры данных будут такими же, как я обычно кодирую. Поэтому мне не нужно менять настроение.
- Моя IDE (PyCharm) понимает связь между конфигурацией и кодом. Ctrl+ Bпозволяет легко переключаться между конфигурацией и кодом.
- Мне не нужно работать с IMO ненужным строгим JSON . Я смотрю на вас двойные кавычки, без запятых и без комментариев.
- Я могу написать тестовые конфигурации в приложении, над которым я работаю, а затем легко перенести их в файл конфигурации, не выполняя преобразование и анализ JSON.
- Можно сделать очень простой сценарий в файле конфигурации, если это действительно необходимо. (Хотя это должно быть очень, очень ограничено.)
Итак, мой вопрос: если я переключаюсь, как я стреляю себе в ногу?
Конечный пользователь не будет использовать файлы конфигурации. Любые изменения в файлах конфигурации в настоящее время передаются в Git и внедряются на наших серверах в рамках непрерывного развертывания. Изменения конфигурации вручную не выполняются, за исключением случаев возникновения чрезвычайной ситуации или ее разработки.
(Я рассматривал YAML , но что-то в этом меня раздражает. Итак, пока это не американский стол.)
источник
Ответы:
Использование языка сценариев вместо конфигурационного файла на первый взгляд выглядит великолепно: у вас есть все возможности этого языка, и вы можете просто
eval()
илиimport
нет. На практике есть несколько ошибок:это язык программирования, который нужно изучать. Чтобы редактировать конфиг, вам нужно знать этот язык достаточно хорошо. Файлы конфигурации, как правило, имеют более простой формат, в котором сложнее ошибиться.
это язык программирования, что означает, что конфигурация может быть трудно отладить. С обычным конфигурационным файлом вы смотрите на него и видите, какие значения предоставляются для каждого свойства. При наличии сценария вам, возможно, потребуется сначала выполнить его, чтобы увидеть значения.
это язык программирования, который затрудняет четкое разделение конфигурации и реальной программы. Иногда вам нужна такая расширяемость, но в этот момент вы, вероятно, скорее ищете настоящую систему плагинов.
это язык программирования, что означает, что конфиг может делать все, что может делать язык программирования. Так что либо вы используете решение для песочницы, которое отрицательно влияет на гибкость языка, либо вы очень доверяете автору конфигурации.
Таким образом, использование сценария для настройки, скорее всего, нормально, если аудитория вашего инструмента - разработчики, например, Sphinx config или setup.py в проектах Python. Другие программы с исполняемой конфигурацией - это оболочки типа Bash и редакторы типа Vim.
Использование языка программирования для конфигурации необходимо, если конфиг содержит много условных разделов или если он предоставляет обратные вызовы / плагины. Использование сценария напрямую вместо eval () - некоторые поля конфигурации имеют тенденцию быть более отлаживаемыми (подумайте о трассировке стека и номерах строк!).
Непосредственное использование языка программирования также может быть хорошей идеей, если ваша конфигурация настолько повторяющаяся, что вы пишете сценарии для автоматической генерации конфигурации. Но, возможно, лучшая модель данных для конфигурации могла бы устранить необходимость в такой явной конфигурации? Например, может быть полезно, если файл конфигурации может содержать заполнители, которые вы позже развернете. Другая особенность, которую иногда можно увидеть, - это несколько файлов конфигурации с различным приоритетом, которые могут перекрывать друг друга, хотя это создает некоторые собственные проблемы.
В большинстве случаев файлы INI, файлы свойств Java или документы YAML гораздо лучше подходят для конфигурации. Для сложных моделей данных может также применяться XML. Как вы заметили, у JSON есть некоторые аспекты, которые делают его непригодным в качестве редактируемого человеком файла конфигурации, хотя это отличный формат обмена данными.
источник
sendmail.cf
. Это указывало бы на то, что использование реального языка сценариев может быть полезным, так как этот язык был фактически разработан для завершения по Тьюрингу. Однако полнота Тьюринга и полнота Тетриса - это две разные вещи, и, хотя ониsendmail.cf
могут вычислять произвольные функции, они не могут отправлять ваши данные/etc/passwd
по сети или форматировать ваш жесткий диск, что Python или Perl смогут.+1 ко всему в ответе амона . Я хотел бы добавить это:
Вы пожалеете об использовании кода Python в качестве языка конфигурации в первый раз, когда захотите импортировать ту же конфигурацию из кода, написанного на другом языке. Например, если код, который является частью вашего проекта и написан на C ++ или Ruby, или что-то еще, нужно перенести в конфигурацию, вам нужно будет связать интерпретатор Python как библиотеку или проанализировать конфигурацию в процессе Python, оба из которые являются неуклюжими, трудными или высокими накладными расходами.
Весь код, который импортирует эту конфигурацию сегодня, может быть написан на Python, и вы можете подумать, что это будет верно и завтра, но знаете ли вы наверняка?
Вы сказали, что будете использовать логику (что угодно, кроме статических структур данных) в своей конфигурации, если это вообще нужно, что хорошо, но если есть хоть что-то, вам будет трудно отменить ее в будущем, чтобы вы может вернуться к декларативному файлу конфигурации.
РЕДАКТИРОВАТЬ для записи: несколько человек прокомментировали этот ответ о том, насколько вероятно или маловероятно, что проект когда-либо будет успешно полностью переписан на другом языке. Справедливо сказать, что полное обратно-совместимое переписывание, вероятно, встречается редко. На самом деле я имел в виду фрагменты одного и того же проекта (и нуждающегося в доступе к одной и той же конфигурации), написанные на разных языках. Например, обслуживающий стек в C ++ для скорости, пакетная очистка базы данных в Python, некоторые сценарии оболочки в качестве клея. Так что подумайте и об этом тоже :)
источник
key=value
присвоениями для config, я не понимаю, почему программа на Java / C ++ не может прочитать файл Python как обычный текстовый файл и проанализировать его так же, если им нужно перейти к чему-то другому в будущее. Я не вижу необходимости в полноценном интерпретаторе Python.Другие ответы уже очень хороши, я просто привожу свой опыт использования в реальных проектах в нескольких проектах.
Pros
Они в основном уже прописаны:
eval
); он работает автоматически даже для более сложных типов данных (в нашей программе у нас есть геометрические точки и преобразования, которые просто выгружаются / загружаются черезrepr
/eval
);Cons
repr
. Это явно плохо.Даже если вы находитесь в Python, изменение файла конфигурации из кода является реальной проблемой, потому что ... хорошо, изменение кода совсем не тривиально, особенно код, который имеет богатый синтаксис и отсутствует в LISP или подобном. Одна из программ , наша имеет конфигурационный файл, Python, изначально написанный вручную, но потом оказалось, было бы полезно , чтобы манипулировать с помощью программного обеспечения (конкретная установка представляет собой список вещей , которые есть способ проще изменить порядок с помощью графического интерфейса пользователя). Это большая проблема, потому что:
Сравните это с JSON, INI или (не дай Бог!) XML, где представление в памяти всегда можно редактировать и записывать либо без потери данных (XML, где большинство анализаторов DOM могут сохранять пробелы в текстовых узлах и узлах комментариев) или по крайней мере, потерять только некоторое форматирование (JSON, где сам формат не позволяет намного больше, чем необработанные данные, которые вы читаете).
Так что, как обычно, нет четкого решения; моя текущая политика по этому вопросу:
если файл конфигурации:
файл Python может быть верной идеей;
если вместо:
формат «только данные» может быть лучшей идеей.
Обратите внимание, что нет необходимости делать один выбор - я недавно написал приложение, которое использует оба подхода. У меня есть почти никогда не модифицируемый файл с настройками, написанными от руки, с преимуществами наличия приятных бонусов Python, и файл JSON для конфигурации, отредактированный из пользовательского интерфейса.
источник
note:
поле, которое игнорируется для конфигурации.curl ... | bash
, это еще меньше хлопот. :-PГлавный вопрос: хотите ли вы, чтобы ваш файл конфигурации был на каком-то полном языке Тьюринга (как, например, Python)? Если вы этого хотите, вы можете также рассмотреть возможность встраивания какого-либо другого языка сценариев (полный по Тьюрингу), такого как Guile или Lua (потому что он может восприниматься как «более простой» для использования или встраивания, чем Python; прочитайте главу о расширении и Встраивание Python ). Я не буду обсуждать это дальше (потому что другие ответы - например, Amon - подробно обсуждали это), но обратите внимание, что встраивание языка сценариев в ваше приложение является основным архитектурным выбором , который вы должны рассмотреть очень рано; Я действительно не рекомендую делать этот выбор позже!
Хорошо известным примером программы, настраиваемой с помощью «сценариев», является редактор emacs GNU (или, возможно, AutoCAD в проприетарной области); так что имейте в виду, что если вы примете сценарии, какой-то пользователь в конечном итоге будет использовать - и, возможно, злоупотреблять, с вашей точки зрения - этой возможностью, и создать сценарий из нескольких тысяч строк; следовательно, выбор достаточно хорошего языка сценариев важен.
Однако (по крайней мере, в системах POSIX) вы можете посчитать удобным включить динамический расчет файла конфигурации во время инициализации (конечно, оставляя бремя нормальной конфигурации вашему системному администратору или пользователю; на самом деле это конфигурация текст, который приходит из некоторого файла или из какой-либо команды). Для этого вы можете просто принять соглашение (и задокументировать его), что путь к файлу конфигурации, начинающийся, например, с a
!
или a,|
на самом деле является командой оболочки, которую вы будете читать как конвейер . Это дает вашему пользователю возможность выбрать любой «препроцессор» или «язык сценариев», с которым он наиболее знаком.(вам нужно доверять своим пользователям вопросы безопасности, если вы принимаете динамически вычисляемую конфигурацию)
Таким образом, в вашем коде инициализации вы
main
(например) примете какой-то--config
аргументconfarg
и получитеFILE*configf;
его из него. Если этот аргумент начинается с!
(то есть, если(confarg[0]=='!')
....), вы должны использоватьconfigf = popen(confarg+1, "r");
и закрыть этот канал сpclose(configf);
. В противном случае вы бы использовалиconfigf=fopen(confarg, "r");
и закрыли этот файл с помощьюfclose(configf);
(не забудьте проверить ошибки). См. Трубу (7) , popen (3) , fopen (3) . Для приложения, написанного на Python, прочитайте о os.popen и т.д ...(документ также для странного пользователя, желающего передать файл конфигурации с именем,
!foo.config
чтобы передать,./!foo.config
чтобы обойтиpopen
хитрость выше)Кстати, такой прием - только удобство (чтобы не требовать от опытного пользователя, например, написания какого-либо сценария оболочки для генерации файла конфигурации ). Если пользователь хочет сообщить об ошибке, он должен отправить вам сгенерированный файл конфигурации ...
Обратите внимание, что вы также можете разработать свое приложение с возможностью использования и загрузки плагинов во время инициализации, например, с помощью dlopen (3) (и вам нужно доверять своему пользователю этот плагин). Опять же, это очень важное архитектурное решение (и вам нужно определить и предоставить довольно стабильный API и соглашение об этих плагинах и вашем приложении).
Для приложения, написанного на языке сценариев, такого как Python, вы также можете принять некоторый программный аргумент для eval или exec или аналогичных примитивов. Опять же, проблемы безопасности - это забота (продвинутого) пользователя.
Что касается текстового формата вашего файла конфигурации (сгенерированного или нет), я считаю, что вам в основном нужно хорошо его документировать (и выбор какого-то конкретного формата не так важен; однако я рекомендую позволить вашему пользователю иметь возможность некоторые-пропущенные комментарии внутри него). Вы можете использовать JSON (предпочтительно с некоторым JSON-парсером, принимающим и пропускающим комментарии с обычным образом
//
до eol или/*
...*/
...), или YAML, или XML, или INI, или ваши собственные вещи. Разбор файла конфигурации достаточно прост (и вы найдете много библиотек, связанных с этой задачей).источник
В дополнение к ответу Амона , вы рассматривали альтернативы? JSON, возможно, больше, чем вам нужно, но файлы Python, вероятно, создадут вам проблемы в будущем по причинам, указанным выше.
Однако в Python уже есть парсер конфигурации для очень простого языка конфигурации, который может удовлетворить все ваши потребности.
ConfigParser
Модуль реализует простой язык конфигурации.источник
Я долгое время работал с некоторым известным программным обеспечением , файлы конфигурации которого написаны на TCL, поэтому идея не нова. Это работало довольно хорошо, поскольку пользователи, которые не знали языка, могли по-прежнему писать / редактировать простые файлы конфигурации с помощью одного
set name value
оператора, в то время как более опытные пользователи и разработчики могли бы использовать сложные приемы.Я не думаю, что «файлы конфигурации могут быть трудно отладить» является действительной проблемой. Пока ваше приложение не вынуждает пользователей писать скрипты, ваши пользователи всегда могут использовать простые назначения в своих файлах конфигурации, что вряд ли более трудно сделать правильно по сравнению с JSON или XML.
Переписать конфиг - это проблема, хотя и не так плохо, как кажется. Обновление произвольного кода невозможно, но загрузка конфигурации из файла, его изменение и сохранение обратно. По сути, если вы выполняете некоторые скрипты в конфигурационном файле, который не предназначен только для чтения, вы просто получите эквивалентный список
set name value
операторов после его сохранения. Хороший намек на то, что это произойдет, - это комментарий «не редактировать» в начале файла.Следует учитывать, что ваши конфигурационные файлы не будут надежно читаться простыми инструментами на основе регулярных выражений, такими как
sed
, но, насколько я понимаю, это уже не так с вашими текущими файлами JSON, так что терять особо нечего.Просто убедитесь, что вы используете соответствующие методы песочницы при выполнении ваших файлов конфигурации.
источник
Помимо всех правильных моментов других хороших ответов здесь (вау, они даже упомянули концепцию Turing-complete), на самом деле есть пара веских практических причин НЕ использовать файл Python в качестве конфигурации, даже когда вы работаете над Python. единственный проект.
Параметры внутри исходного файла Python технически являются частью исполняемого исходного кода, а не файлом данных только для чтения. Если вы идете по этому пути, вы, как правило, делаете это
import config
, потому что такого рода «удобство», вероятно, было одной из основных причин, по которой люди начали с использования файла Python в качестве конфигурации в первую очередь. Теперь вы стремитесь зафиксировать этот config.py в своем репозитории, иначе ваш конечный пользователь столкнется с запутанной ошибкой ImportError, когда он попытается запустить вашу программу в первый раз.Предполагая, что вы на самом деле фиксируете этот config.py в своем репо, теперь члены вашей команды, вероятно, будут иметь разные настройки в другой среде. Представьте себе, что когда-нибудь какой-нибудь участник случайно поместит свой локальный файл конфигурации в репозиторий.
Наконец, что не менее важно, ваш проект может иметь пароли в файле конфигурации. (Это дискуссионная практика сама по себе, но в любом случае это происходит.) И если ваш файл конфигурации существует в репо, вы рискуете передать свои учетные данные в публичное репо.
Теперь, используя файл конфигурации только для данных, такой как универсальный формат JSON, можно избежать всех трех вышеупомянутых проблем, потому что вы можете разумно попросить пользователя создать свой собственный файл config.json и вставить его в вашу программу.
PS: это правда, что JSON имеет много ограничений. 2 из ограничений, упомянутых ОП, могут быть решены с помощью некоторой креативности.
И у меня обычно есть заполнитель, чтобы обойти правило запятой. Нравится:
источник