Наскільки поганою є ідея використовувати файли Python як файли конфігурації?

Я завжди використовував файли JSON для налаштування своїх програм. Я почав використовувати їх, коли я кодував багато Java, і тепер я працюю в основному на розробці Python на стороні сервера і даних і не впевнений, що JSON є правильним шляхом .

Я бачив, як Селера використовує фактичні файли Python для конфігурації. Спочатку я скептично ставився до цього. Але ідея використання простих структур даних Python для конфігурації починає зростати на мене. Деякі плюси:

  • Структури даних будуть такими ж, як я зазвичай кодую. Таким чином, мені не потрібно змінювати налаштування.
  • Моя IDE (PyCharm) розуміє зв'язок між конфігурацією та кодом. Ctrl + B дозволяє легко переходити між конфігурацією та кодом.
  • Не потрібно працювати з IMO зайвим JSON . Я дивлюся на ваші подвійні лапки, без комах і без коментарів.
  • Я можу писати тестові конфігурації в програмі, на якій я працюю, а потім легко переносити їх у файл конфігурації без необхідності перетворення та аналізу JSON.
  • Можна зробити дуже простий скрипт у файлі конфігурації, якщо це дійсно необхідно. (Хоча це має бути дуже, дуже обмеженим).

So, my question is: If I switch, how am I shooting myself in the foot?

Жоден некваліфікований кінцевий користувач не використовуватиме файли конфігурації. Будь-які зміни файлів конфігурації в даний час передані Git і виводяться на наші сервери як частина безперервного розгортання. Немає ручних змін у конфігурації, якщо не існує надзвичайної ситуації або вона перебуває у розробці.

(Я розглядав YAML , але щось про це дратує мене. Отже, на даний момент він виключений з американського столу.)

69
@bishop "off table" у англійському англійському означає більше не розглядатися, з парламентських пропозицій, які ставляться на стіл в середині палати громад для обговорення, а отже, і "подано на обговорення" (протокол парламенту 1799 - books.google.co.uk/… ), AFAIK значення США є однаковим, але я не знаю, чи є у вас таблиця в парламенті .
додано Автор Rob Hunter, джерело
Не достатньо реплікації (або практичного досвіду з моєю пропозицією), щоб відповісти, але вас може зацікавити щось подібне додано Автор Alqin, джерело
Побічне питання щодо останнього рядка: що таке "американський стіл"? Google не допомагає мені знайти значення цього виразу.
додано Автор Stuart, джерело
Якщо уникнути вашого останнього пункту - додавання сценаріїв - тоді все, що ви використовуєте для Python, є "JSON, але більш зручним для користувача". Якщо це так, просто використовуйте ast.literal-eval, і інтерпретатор python буде застосовувати, щоб файл мав лише дані, без виконуваного коду. Я використовую його таким чином, і це дуже приємно. Єдина проблема, якщо ви робите синтаксичну помилку, ast.literal_eval не буде правильно розповісти вам, де він знаходиться. Полювання на неї стає потворним. Зверніть увагу, що я навіть не зберігаю їх як .py файли - я позначаю їх .txt, щоб зробити те, що він не виконується, більш очевидний.
додано Автор Bruce, джерело
@ AndréChristofferAndersen: Один із варіантів, який я ніколи не намагався спробувати - це використовувати синтаксис Python, але обмежити його якимось чином і інтерпретувати AST, а не оцінювати код. Таким чином, ви можете обмежити те, що користувач може і не може робити, забезпечуючи при цьому більшу гнучкість, ніж, скажімо, JSON.
додано Автор Phil Brooks, джерело
Обов'язкова сторона згадує, що JSON не має бути строгим. Різноманітні бібліотеки JSON підтримують зап'ястки та коментарі у стилі JS. Він не буде сумісним для зовнішнього використання, але для конфігураційного файлу це чудово. Також існує безліч інших мов конфігурації, подібних до JSON, наприклад, конфігурація TypeSafe . Це надбудова JSON з різноманітними додатковими функціями.
додано Автор Vincent Buck, джерело
Існує протиріччя між "некваліфікованими користувачами" і "сценаріями". Користувачам "некваліфікованих" має бути наданий найпростіший і найбільш захищений від кулі формат, як-от JSON або INI, причому вся розширена інтерпретація явно обмежена і контролюється вашою програмою. Досвідчені користувачі можуть просто написати модуль Python для вашої програми (особливо якщо ви дозволяєте скрипти розширення), не поєднуючи його з конфігураційними файлами.
додано Автор Rorick, джерело
Що ви маєте на увазі під "поза американським столом"?
додано Автор innaM, джерело
@PeterMortensen - Він має на увазі американську англійську ідіому "поза столом". Іншими словами, це не розглядається як можливість.
додано Автор Ben, джерело
Ваша проблема - некваліфіковане. Зловмисне.
додано Автор Schroeder, джерело
Використовуйте JSON або YAML або подібні. Якщо люди хочуть використовувати макроси і такі в конфігурації, вони можуть досягти цього, написавши скрипт для створення конфігурації.
додано Автор Alireza Abdollahi, джерело
@PeteKirkham, afaik тільки до таблиці sth має протилежні значення в AE і BE.
додано Автор Abdul jalil, джерело
Використовуйте JSON як конфігурацію. Багато мов розуміють JSON (включаючи Python, тому можна стверджувати, що він використовує підмножину Python), він короткий і читабельний. І ви не захочете спробувати написати більш складний «код» у ваших конфігураційних файлах.
додано Автор ChuckCottrill, джерело
@Celada Схоже, виходить з виступу Ніксона: додано Автор parasietje, джерело
Це точна протилежність поганій ідеї
додано Автор Miles Rout, джерело
@Blrfl Безперечно, однакові проблеми стосуються будь-якої програми, яку користувач має право змінювати, незалежно від того, чи є її конфігурація виконуваною.
додано Автор Casey, джерело
"Отже, поки що він відірваний від американського столу". === "Так що зараз, як кажуть американці, стоїть".
додано Автор bishop, джерело
Якщо вам не подобаються JSON, YAML або XML, ви повинні ознайомитися з edn . Він подібний до JSON, за винятком менш деталізованих (без коми (фактично комами є пробіли, тому їх можна розміщувати в будь-якому місці)), має більш розширені типи (тип ключового слова з необов'язковими просторами імен, наборів, типів даних) і розширюється зі спеціальними типами. Синтаксичний аналізатор для python .
додано Автор Ultimate Hawk, джерело
Якщо вам не подобається JSON, ви повинні спробувати yaml. Мені дуже подобається конфіг. особливо, коли задіяні великі рядки, YAML є більш читаним, ніж JSON.
додано Автор Christian Sauer, джерело
Крім того, існує TOML, який використовується в конфігураціях контейнерів Cargo (Rust), і доступний парсер через pip install toml .
додано Автор Etherlind, джерело
@Blrfl Правда. Це одна з моїх головних проблем. В даний час, якщо ви можете змінити файли конфігурацій, ви також можете змінити код. Проблема, яку я бачу, полягає в тому, що ми в майбутньому матимемо більший розподіл обов'язків, коли конфігураційні файли передаються між членами команди, деякі з яких можуть робити оновлення кодування, а інші - не. Це далеко, але може бути справа в майбутньому. Файли налаштування на основі Python будуть проблемою безпеки.
додано Автор logan, джерело
Існує також Django, веб-фреймворк python, який використовує файл конфігурації python.Дозволяє повторно використовувати якусь змінну, наприклад, багато проекту мають значення "ROOT" для шляху проекту і використовують його для більш змінної з os.path. join (ROOT, шлях).
додано Автор Csaba Zsolnai, джерело
Фундаментальна проблема полягає в тому, що Python є Turing-повною і JSON не є. Таким чином, жодна програма не може надійно прогнозувати поведінку сценарію python. Якщо ваша IDE, схоже, розуміє Python, вона не розуміє його в тому ж сенсі, що програмне забезпечення може зрозуміти файл JSON. Бірф каже: Некваліфіковані - це не ваша проблема. Згубним є. Щоб посилити це, є легкі автоматизовані способи захисту від зловмисного JSON, але немає ніякого способу, навіть принципово, дати автоматизований захист від зловмисного пітона. Здається, що ви дійсно хочете, щоб це була більш виразна мова Тьюрінга.
додано Автор Ben, джерело
Як реагує ваша програма, якщо ви вкладете rm -rf/* у сценарій налаштування Python? :-)
додано Автор Dominique, джерело

6 Відповіді

Використання мови сценаріїв замість файлу налаштувань виглядає чудово на перший погляд: у вас є повна сила цієї мови і ви можете просто eval() або import . На практиці є кілька причин:

  • це мова програмування, яку потрібно вивчити. Щоб відредагувати конфігурацію, потрібно добре знати цю мову. Файли конфігурації зазвичай мають простіший формат, який важче отримати неправильно.

  • це мова програмування, що означає, що налагодження може бути важким. З нормальним файлом конфігурації ви дивитеся на нього і подивитися, які значення надаються для кожного властивості. За допомогою сценарію вам, можливо, спочатку потрібно виконати його, щоб побачити значення.

  • це мова програмування, що ускладнює підтримку чіткого розмежування між конфігурацією та дійсною програмою. Іноді вам потрібна така розширюваність, але на цьому етапі ви швидше за все шукаєте справжню систему плагінів.

  • це мова програмування, що означає, що конфігурація може робити все, що може робити мова програмування. Таким чином, або ви використовуєте пісочне рішення, яке зводить нанівець більшу гнучкість мови, або ви довіряєте автору конфігурації.

Таким чином, використання сценарію для налаштування, ймовірно, гаразд, якщо аудиторія вашого інструменту є розробниками, наприклад, Конфігурація Sphinx або setup.py в проектах Python. Інші програми з виконуваною конфігурацією - це оболонки типу Bash, а також редактори, такі як Vim.

Використання мови програмування для конфігурації необхідно, якщо конфігурація містить багато умовних розділів, або якщо вона надає зворотні виклики/плагіни. Використання скрипту безпосередньо замість eval() - деяке поле конфігурації має тенденцію бути більш налагоджуваною (подумайте про сліди стека і числа рядків!).

Безпосереднє використання мови програмування також може бути гарною ідеєю, якщо ваш конфігурація настільки повторюється, що ви пишете сценарії для автоматичного створення конфігурації. Але, можливо, краща модель даних для конфігурації може видалити необхідність такої явної конфігурації? Наприклад, може бути корисно, якщо конфігураційний файл може містити заповнювачі, які ви пізніше розгортаєте. Іншою особливістю, яка іноді спостерігається, є декілька файлів конфігурацій з різним пріоритетом, які можуть перекривати один одного, хоча це і створює певні проблеми.

У більшості випадків файли INI, файли властивостей Java або документи YAML набагато краще підходять для налаштування. Для складних моделей даних може також застосовуватися XML. Як ви вже зазначали, у JSON є деякі аспекти, які роблять його непридатним як файл конфігурації, що можна редагувати для людини, хоча це є форматом для точного обміну даними.

89
додано
@ JörgWMittag: "Вся мова, заснована на залежному типі, полягає в тому, що ви можете вирішувати довільні властивості програм" ... uh, залежне друкування є нерозв'язним, якщо ви не додасте додаткових обмежень. Це буквально у вступі Вікіпедії.
додано Автор Phil Brooks, джерело
@ JörgWMittag: Я трохи поглиблюю це. У тому місці, де ви спостерігаєте, що ваша конфігурація починає розробляти функції "внутрішньої платформи", тоді почніть роздумувати, чи потрібно просто використовувати кращу платформу/мову. Так, наприклад, якщо ви використовуєте JSON конфігурацію, то шлях до того, як завершиться Тьюрінг, ви іноді виявляєте, що там, де ваш конфігурація вказує ім'я файлу, ви хочете надати способи сказати, в JSON, "викликати певні функції з os.path з цими параметрами, щоб дати ім'я файлу ". Ви починаєте бажаючи , що ви використовували Python, навіть якщо це не правильне рішення (ще) :-)
додано Автор TraumaPony, джерело
Є кілька форматів файлів конфігурації, які "випадково завершують Тьюрінг", найвідоміше - sendmail.cf . Це вказує на те, що використання реальної скриптової мови може бути корисним, оскільки це було фактично розроблене для завершення Тьюрінга. Однак , повноту Тьюрінга та "Повнота Тетріс" - це дві різні речі, і хоча sendmail.cf може обчислювати довільні функції, не надішліть ваш /etc/passwd через мережу або відформатуйте ваш жорсткий диск, який зможе Python або Perl.
додано Автор Lawrence B. Crowell, джерело
@ Theraot: "Total" означає, що він завжди повертається. Машина Тьюринга може виконувати нескінченний цикл, тобто вона має можливість не повертатися. Отже, Ідріс не може робити все, що робить машина Тьюринга, а це означає, що це не так. Це стосується всіх залежних від мови мов. Весь сенс залежної типи мови полягає в тому, що ви можете вирішувати довільні властивості про програми, тоді як у мові Тьюринга ви не можете вирішити навіть тривіальні властивості, наприклад, "чи зупиняється програма?" Загальна кількість мов за визначенням не Turing-повно, тому що машини Turing є частковими.
додано Автор Lawrence B. Crowell, джерело
Визначення "Turing-complete" - це "можна реалізувати машину Тьюринга". Визначення "Тетріс-повний" це "можна здійснити тетріс". Вся суть цього визначення полягає в тому, що повнота Тьюринга просто не дуже цікава в реальному світі. Є багато корисних мов, які не є Тьюрінгом, наприклад, HTML, SQL (до 1999 р.), Різні DSL і т.д. ОС, середовище, всі з яких важливі.
додано Автор Lawrence B. Crowell, джерело
Причина, чому Едвін Бреді використовував цей приклад, полягає в тому, що багато людей думають, що мови, які не є Тьюрінговими, не можуть бути використані для програмування загального призначення. Я сам думав, що теж, адже багато цікавих програм є по суті нескінченними циклами, які ми не хочемо припиняти , наприклад, сервери, операційні системи, петлі подій в графічному інтерфейсі, ігрові петлі. Багато програм обробляють нескінченні дані, напр. потоки подій. Раніше я думав, що ти не можеш писати це загальною мовою, але я дізнався, що ти можеш , і тому я вважаю гарною ідеєю мати термін для цієї можливості.
додано Автор Lawrence B. Crowell, джерело
"що ускладнює підтримку чіткого розмежування між конфігурацією та фактичною програмою" Щоб бути справедливими, деякі платформи створюють складні конфігураційні файли, які роблять це. бурчить про постачальників ADO.NET і ASP.NET
додано Автор jmibanez, джерело
@ JörgWMittag Я бачу, я не знав, що "загальний" означає, що в контексті. Я припускаю, що ви маєте рацію щодо Ідріса. Незважаючи на те, що туринський повний перелік був наданий мовам, які вимагають введення даних з боку користувача ... назад до CSS, він не може робити циклів, але він може запрограмувати правила, якщо тільки користувач продовжує натискати (як тип годинника) введення). Я згоден, що це не дуже корисно, але те, з чого я приходжу, це те, що мова без побічних ефектів може бути завершена. Тетріс не може бути чудовою альтернативою, оскільки вам не потрібно "надсилати/etc/passwd через мережу або форматувати жорсткий диск", щоб отримати Tetris.
додано Автор Joel, джерело
@ JörgWMittag Турін-завершеність не означає, що можна надсилати речі по мережі або отримувати доступ до жорсткого диска. Тобто, завершенність Турина стосується обробки не про I/O. Наприклад, CSS вважається Турін завершеним, але він не зіпсується з вашим постійним сховищем. Ви сказали в іншому місці, що "Ідріс - це цілком чиста функціональна мова, тому це за визначенням не Тьюрінг-повна", що не слідує, і очевидно, що Турін завершений. Я був переконаний, що ваше використання Testris-завершення означало, що мова була завершена в Туріні, але не в змозі зробити повний ввід/висновок ... здається, це не те, що ви маєте на увазі.
додано Автор Joel, джерело
Короткий спосіб вказати це: Виразна потужність - це помилка, а не функція.
додано Автор R.., джерело
Хорошим прикладом цього є система ін'єкцій залежностей. Головне, що вони вам дають - це перенесення будівництва на іншу мову. Нічого не мова не могла зробити. Але тепер змішана конструкція та поведінка менш імовірно, оскільки це відбувається на двох різних мовах. Конфігурація і код часто розділені мовою з тієї ж причини.
додано Автор candied_orange, джерело
@ JörgWMittag Крім того, ідея про те, що в (загальному чи ні) мові DT "ви можете вирішити довільні властивості про програми" є помилковою. Ви можете вирішити, чи вони зупиняться чи ні (тобто вони це роблять), але ви не можете обов'язково вирішити, якщо, скажімо, функція від натуральних чисел завжди досягає певної цінності.
додано Автор Καrτhικ, джерело
@ JörgWMittag: це не зовсім вірно, що всі залежні від мови мови є загальними, це просто дуже часто, оскільки перевірка типу не вдається завершити вважається поганою формою. (Я вважаю "залежним типом" і "загальним" схожим на "ледачий" і "чистий" в тому, що немає теоретичної причини вони повинні йти разом, це просто дуже незручно, якщо вони цього не роблять).
додано Автор Καrτhικ, джерело
@Theraot Тюрінг (як у чоловіка) не Турин .
додано Автор Ashok, джерело
Дякую! Дуже інформативний. Я подумаю. Я розглянув файли INI, і python, мабуть, має багато приємних можливостей/бібліотек для їх обробки.
додано Автор logan, джерело

+1 до всього в відповідь amon . Я хочу додати це:

Ви будете шкодувати з використанням коду Python як мови налаштування вперше, коли ви хочете імпортувати ту ж конфігурацію з коду, написаного на іншій мові. Наприклад, якщо код, який є частиною вашого проекту, і він написаний на мові C ++ або ruby або щось інше, потрібно втягнути в конфігурацію, вам потрібно зв'язати інтерпретатор Python як бібліотеку або розібрати конфігурацію в співпроцесі Python, як які незручні, складні або високі.

Весь код, який імпортує цю конфігурацію сьогодні, може бути написаний на Python, і ви можете подумати, що це буде вірно і завтра, але чи знаєте ви точно?

Ви сказали, що ви використовуєте логіку (будь-що інше, що є статичною структурою даних) у вашій конфігурації, коли це буде дуже важливо, але це добре, але якщо ви хочете зробити це, вам буде важко в майбутньому скасувати її. може повернутися до декларативного файлу конфігурації.

EDIT for the record: several people have commented on this answer about how likely or unlikely it is that a project would ever be successfully completely rewritten in another language. It's fair to say that a complete backward-compatible rewrite is probably rarely seen. What I actually had in mind was bits and pieces of the same project (and needing access to the same configuration) being written in different languages. For example, serving stack in C++ for speed, batch database cleanup in Python, some shell scripts as glue. So spend a thought for that case too :)

49
додано
@nneonneo, звичайно. Завжди є обхідні шляхи. Це все ще технічний борг.
додано Автор Stuart, джерело
Гаразд, дозвольте мені спробувати пояснити, редагуючи ...
додано Автор Stuart, джерело
@Mast, вибачення, але я не слідую. Ім'я файлу (незалежно від того, чи закінчується він у .py) ні тут, ні там. Точка, яку я намагаюся зробити, полягає в тому, що якщо він написаний на Python, то вам знадобиться інтерпретатор Python, щоб його прочитати.
додано Автор Stuart, джерело
@JonBentley Я ще не бачив жодного реального світового проекту, який підтримував би сумісність, коли він був повністю переписаний на іншій мові. Пекло я не можу подумати про будь-який успішний проект що був повністю rewritten щоб почати з (я подумав ми вивчили що урок з Netscape, або Borland .. ok можливо ми не довідуємось що урок дуже добре). Це вражає мене як теоретичне занепокоєння. І якщо backcomp не є проблемою (як це було б, якщо б ви сказали, що перенесли на Android), той факт, що вам доведеться перенести весь проект гномів будь-які витрати на переосмислення і переписати вашу файлову систему конфігурації.
додано Автор Kyle Hodgson, джерело
@JonBentley Я думаю, що це хороші моменти, але бібліотеки часто передбачають додаткові/зовнішні залежності, які можуть бути небажаними або недоступними (наприклад, системний адміністратор занадто стурбований тим, що встановлення модуля вимагатиме оновлень для інших і може "розбити виробництво"). Деякі мови можуть бути більш чутливими до цього (наприклад, Perl), ніж інші.
додано Автор Vineel Adusumilli, джерело
@JonBentley Я вважаю, що занепокоєння буде актуальним, якщо ви плануєте робити багатомовні проекти. Я не отримав такого враження від ОП. Крім того, використання текстових файлів для конфігурації потребує додаткового коду (на всіх мовах) для фактичного аналізу/перетворення значень. Технічно, якщо вони обмежують сторону Python до key = value призначень для конфігурації, я не розумію, чому програма Java/C ++ не змогла прочитати файл Python як звичайний текстовий файл і розібрати її те ж саме, якщо їм потрібно перейти на щось інше в майбутньому. Я не бачу потреби в повноцінному інтерпретаторі Python.
додано Автор Vineel Adusumilli, джерело
@ray \ tТаким чином, якщо ви збираєтеся обмежитися key = value для цієї мети, python вже має configparser і java має ini4j , тощо і т.д. Або просто перейдіть json, як в першу чергу запропонував ОР.
додано Автор Izkata, джерело
@Mast Я думаю, ви розбираєте його неправильно. Точка, яку я взяв з цієї відповіді (як оригінальної, так і відредагованої), полягає в тому, що вибір для запису конфігураційних файлів на мові програмування полягає в тому, що це ускладнює написання коду на іншій мові. Напр. Ви вирішили перенести програму на Anrdoid/iPhone і використовуватиме іншу мову. Ви повинні (a) покладатися на інтерпретатор Python у додатку для мобільного телефону (не ідеально), (b) переписувати конфігурацію у незалежному від мови форматі та переписувати код Python, який його використовував, або (c) підтримувати два формати конфігурації, що йдуть вперед.
додано Автор Jon Bentley, джерело
@ray True, але відповідь залишається корисною з огляду на те, що питання не повинні бути застосовними лише до особи, яка їх публікує. Якщо ви використовуєте стандартизований формат (наприклад, INI, JSON, YAML, xml тощо), то, швидше за все, скористайтеся існуючою бібліотекою аналізування, ніж писати власну. Це зменшує додаткову роботу до класу адаптерів для взаємодії з бібліотекою розбору. Якщо ви обмежуєтеся значенням key = value, то це позбавляє більшість причин використання операційної системи Python у першу чергу, і ви можете просто йти з визнаним форматом.
додано Автор Jon Bentley, джерело
Мені довелося зробити це кілька років тому, коли інструмент, написаний на Lua, використовував сценарій Lua як свій конфіг, тоді вони хотіли, щоб ми написали новий інструмент у C#, і спеціально попросив нас використовувати скрипт налаштування Lua. У них було всього 2 лінії, які були фактично програмованими і не простими x = y, але я все ще мав дізнатися про перекладачі Lua з відкритим вихідним кодом для .net через них. Це не суто теоретичний аргумент.
додано Автор Der Zauberer von Oz, джерело
Якщо біти записані на інших мовах, ви не можете визначити внутрішній протокол для передачі конфігурації цим іншим бітам? Цілком ймовірно, ви збережете Python (або будь-який інший) як клей високого рівня, який пов'язує решту разом, і в цьому випадку однією з його обов'язків буде розбір конфігурації і передача його іншим компонентам.
додано Автор Paul-Armand Verhaegen, джерело
Це саме той аргумент, який люди мали проти xml 10 років тому.
додано Автор Dhruv Ghulati, джерело
@JonBentley Я думаю, що має сенс, спасибі.
додано Автор Rajendra Rathore, джерело
Або це було не ясно з вашої відповіді, або я просто розбираю її неправильно. У будь-якому випадку, чому це важливо, він потребує інтерпретатора Python? OP вказує, що він зараз знаходиться в середовищі Python, тому він доступний. Так само відбувається за замовчуванням у системах GNU/Linux, тому що він використовується для конфігурації ОС. Так що я не здивований, OP хоче зробити щось подібне для своїх додатків.
додано Автор Rajendra Rathore, джерело
Одним з правил програм Python є те, що вони повинні мати розширення .py. Так, так, ви будете знати, що це написано на Python. Звичайно, файл може просто містити JSON і все ще працювати за призначенням, але це не так.
додано Автор Rajendra Rathore, джерело

Інші відповіді вже дуже хороші, я просто принесу свій досвід використання реального світу в декількох проектах.

Плюси

Вони в основному вже прописані:

  • якщо ви перебуваєте в програмі Python, синтаксичний аналіз - це вітер ( eval ); вона працює автоматично навіть для більш складних типів даних (у нашій програмі ми маємо геометричні точки та перетворення, які відправляються/завантажуються відмінно через repr / eval );
  • Тривіальне створення "підробленого конфігурації" лише кількома рядками коду;
  • у вас є кращі структури і, IMO, кращий синтаксис, ніж JSON (це навіть просто коментарі і не потрібно вводити подвійні лапки навколо ключів словника - це велика переможність читання).

Мінуси

  • malicious users can do anything that your main program can do; I don't Мінусиider this much of a problem, since generally if a user can modify a configuration file he/she can already do whatever the application can do;
  • if you are no longer in a Python program, now you have a problem. While several of our configuration files remained private to their original application, one in particular came to store information that is used by several different programs, most of which are currently in C++, which now have a hacked-together parser for an ill-defined small subset of Python repr. This is obviously a bad thing.
  • Even if your program remains in Python, you may change Python version. Let's say your application started in Python 2; after lots of testing you managed to migrate it to Python 3 - unfortunately, you didn't really test all of your code - you have all the configuration files lying around on your customers' machines, written for Python 2, and on which you don't really have control. You cannot even provide a "compatibility mode" to read old configuration files (which is often done for file formats), unless you are willing to bundle/call the Python 2 interpreter!
  • Even if you are in Python, modifying the configuration file from code is a real problem, because... well, modifying code is not trivial at all, especially code that has a rich syntax and is not in LISP or similar. One program of ours has a configuration file that is Python, originally written by hand, but which later turned out it would be useful to manipulate via software (a particular setting is a list of things that is way simpler to reorder using a GUI). This is a big problem, because:

    • even just performing a parse→AST→rewrite roundtrip is not trivial (you'll notice that half of the proposed solutions are later marked as "obsolete, do not use, does not work in all cases");
    • even if they worked, AST is way too low-level; you are generally interested in manipulating the result of the computations performed in the file, not the steps that brought to it;
    • which brings us to the simple fact that you cannot just edit the values you are interested with, because they may be generated by some complex computation that you cannot understand/manipulate through your code.

    Compare this with JSON, INI or (God forbid!) XML, where the in-memory representation can always be edited and written back either without loss of data (XML, where most DOM parsers can keep whitespace in text nodes and comment nodes) or at least losing just some formatting (JSON, where the format itself doesn't allow much more than the raw data you are reading).


Отже, як завжди, немає чіткого рішення; Моя поточна політика щодо цього питання:

  • if the configuration file is:

    • surely for a Python application and private to it - as in, nobody else will ever try to read from it;
    • hand-written;
    • coming from a trusted source;
    • using target application data types is really a premium;

    a Python file may be a valid idea;

  • if instead:

    • there may be the possibility of having some other application read from it;
    • there is the possibility that this file may be edited by an application, possibly even my application itself;
    • is provided by an untrusted source.

    a "data only" format may be a better idea.

Зверніть увагу, що не потрібно робити жодного вибору - я нещодавно написав програму, яка використовує обидва підходи. У мене є майже ніколи не змінений файл з першим налаштуванням, рукописними налаштуваннями, де є переваги хороших бонусів Python, і файл JSON для конфігурації, відредагований з інтерфейсу.

20
додано
дуже гарна точка про генерацію або перезапис конфігурації! Але кілька форматів, окрім XML, можуть зберігати коментарі у виході, що я вважаю надзвичайно важливим для конфігурації. Інші формати іноді вводять поле note: , яке ігнорується для конфігурації.
додано Автор amon, джерело
@ Дмитрий Григорьєв: і це саме те, що може дозволити комусь повністю зруйнувати виробничу систему в перший день роботи. Якщо 'eval' - ваш синтаксичний аналізатор, це означає, що немає можливості перевірити його на наявність проблем, перш ніж він буде прочитаний. (з тієї ж причини, чому сценарії оболонки настільки погані у виробництві). INI, YAML або JSON є безпечними в цьому відношенні.
додано Автор tom, джерело
@DmitryGrigoryev: я хочу сказати, що якщо ваш тип жертви достатньо дурний, щоб сліпо скопіювати файл конфігурації, ви, ймовірно, можете підставити його/її робити все, що на їхній машині, з менш косими методами ("вставте це в консоль виправити проблему! "). Крім того, навіть з не виконуваними конфігураційними файлами є великий потенціал для шкоди - навіть просто зловмисно вказуючи на реєстрацію критичних файлів (якщо програма працює з достатньою кількістю привілеїв), ви можете нанести хаос на систему. Ось чому я вважаю, що на практиці це не багато різниці в умовах безпеки.
додано Автор Risnotmean, джерело
@Wildcard: Я не згадував YAML, головним чином тому, що (1) я "зібрав" його разом з іншими мовами "тільки для даних" і (2) я не маю багато досвіду з перших рук. Я доторкнувся до конфігураційного файлу тут і там, і основний синтаксис залишив мене сприятливо здивованим, хоча, коли я пішов вниз, щоб перевірити повну граматику, він погладив мене як занадто складний (і з більшою кількістю кутових випадків, ніж мені здавалося необхідним). Тим не менш, це шлях більш читаний альтернативою JSON, так що, звичайно, це "на столі".
додано Автор Risnotmean, джерело
@ Дмитро Григорьєв: якщо ви прагнете до цієї мети, ви можете також сказати своїй жертві, щоб скопіювати деякі закрутки ... | bash , це навіть менше клопоту. :-P
додано Автор Risnotmean, джерело
Ви не згадуєте YAML. Я завжди думав про YAML як про "Python конфігураційних файлів", оскільки пробіли є значними аналогічними способами. FAR легше змінити вручну, ніж JSON. І ви не дозволяєте виконання довільного коду.
додано Автор Wildcard, джерело
@MatteoItalia Очевидно, curl ... | bash має таку ж проблему, вона підходить лише для URL-адрес, яким ви повністю довіряєте. Хоча я бачив тільки цю конструкцію, що використовується для інсталяції програмного забезпечення, і якщо довіряти програмному забезпеченню, то, як правило, немає підстав для недовіри до сценарію установки. Це те, що ви мали на увазі під з метою досягнення цієї мети ?
додано Автор Dhruv Ghulati, джерело
"якщо користувач може змінити файл конфігурації, він/вона вже може робити все, що може робити програма", - це не зовсім так. Як щодо тестування, ніж блискучий конфігураційний файл, кого ви не знаєте, завантажили на pastebin?
додано Автор Dhruv Ghulati, джерело

The main question is: do you want your configuration file to be in some Turing complete language (like Python is)? If you do want that, you might also consider embedding some other (Turing complete) scripting language like Guile or Lua (because there could be perceived as "simpler" to use, or to embed, than Python is; read the chapter on Extending & Embedding Python). I won't discuss that further (because other answers -e.g. by Amon- discussed that in depth) but notice that embedding a scripting language in your application is a major architectural choice, that you should consider very early; I really don't recommend making that choice later!

Відомим прикладом програми, що можна налаштувати через "скрипти", є редактор GNU emacs AutoCAD у власному регіоні); так що знайте, що якщо ви приймаєте сценарії, деякі користувачі зрештою використають - і, можливо, зловживають, у вашій точці зору - цю об'єкт широко і роблять скрипт з декількох тисяч рядків; отже, важливим є вибір досить гарної мови сценаріїв.

Проте (принаймні, у системах POSIX) можна вважати зручним, якщо файл конфігурації “динамічно обчислюється під час ініціалізації (звичайно, залишається тягар нормальної конфігурації для системного адміністратора або користувача, насправді це конфігурація text , яка надходить з деяких файлів або з деяких команд). Для цього можна просто прийняти конвенцію документ ), що шлях конфігураційного файлу починається з напр. ! або | насправді є командою , яку ви читаєте як . Це залишає ваш користувач з можливістю вибору будь-якого "препроцесора" або "мови сценаріїв", з яким він найбільш знайомий.

(потрібно довіряти користувачеві щодо проблем безпеки, якщо ви приймаєте динамічно обчислену конфігурацію)

Таким чином, у коді ініціалізації ваш 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 , щоб обійти підказка вище)

Нарешті, такий прийом - це лише зручність (щоб не вимагати від просунутих користувачів, наприклад, кодувати сценарій оболонки, щоб генерувати файл налаштування ). Якщо користувач бажає повідомити про будь-яку помилку, він повинен надіслати вам згенерований файл конфігурації ...

Зверніть увагу, що ви також можете розробити свою програму з можливістю використання та завантаження плагінів під час ініціалізації, напр dlopen (3) (і ви повинні довіряти своєму користувачеві) про цей плагін). Знову ж таки, це дуже важливе архітектурне рішення (і вам потрібно визначити і надати досить стійкий API і правила щодо цих плагінів і вашої програми).

For an application coded in a scripting language like Python you could also accept some program argument for eval or exec or similar primitives. Again, the security issues are then the concern of the (advanced) user.

Regarding the textual format for your configuration file (be it generated or not), I believe that you mostly need to document it well (and the choice of some particular format is not that important; however I recommend to let your user be able to put some -skipped- comments inside it). You could use JSON (preferably with some JSON parser accepting and skipping comments with usual // till eol or /*...*/ ...), or YAML, or XML, or INI or your own thing. Parsing a configuration file is reasonably easy (and you'll find many libraries related to that task).

8
додано
+1 для згадки про повноту Тьюринга мов програмування. Деякі цікаві роботи показують, що обмеження обчислювальної потужності вхідного формату є запорукою забезпечення рівня обробки вхідних даних. Використання повної мови програмування Тьюринга йде у зворотному напрямку.
додано Автор Sideshow Bob, джерело

Додавання до відповідь amon , чи розглядали ви альтернативи? JSON, можливо, більше, ніж вам потрібно, але файли Python, ймовірно, дадуть вам проблеми в майбутньому з причин, згаданих вище.

Однак у Python вже є синтаксичний аналізатор для дуже простої мови налаштування, яка може задовольнити всі ваші потреби. Модуль ConfigParser реалізує просту мову налаштування.

2
додано
@CodeMonkey Я б сказав, що набагато краще не очікувати від користувачів редагування конфігураційних файлів взагалі, але надавати користувальницькому інтерфейсу можливість налаштувати конфігурацію, навіть якщо вона знаходиться на рівні сканування chrome://flags/краще, ніж конфігураційний файл. У який момент конфігураційний файл більше не є відповідним - більшість систем, які я побудував протягом останніх десяти років, використовують базу даних з повним аудитом, так як якщо хтось змінює налаштування, і це порушує систему, яку власники хочуть знати про це . І так, якщо ви створили систему підтримки для китайської атомної станції, вони будуть наполягати на використанні не-ASCII символів у своєму конфігурації.
додано Автор Rob Hunter, джерело
@ jpmc26 В основному, так, я використовую сучасні формати, в яких вказано поведінку всіх реалізацій, наприклад JSON або XML, а не використовує реалізацію, відмінну від очікувань користувача. Ви не можете уникнути очікувань користувача від файлу INI, який можна редагувати в Notepad в латинському кодуванні. Мої користувачі будуть помістити в нього смайлики. Якщо ви не повинні мати справу з цим, то ще раз я стверджую, ви можете використовувати те, що вам подобається, навіть спадщини з 16-бітної ери Windows.
додано Автор Rob Hunter, джерело
@ jpmc26 Я витратив достатньо часу на виправлення проблем у системах, які хтось думав, що "шанси, що це не станеться", що я уникаю таких помилок. Ви вільні робити інше.
додано Автор Rob Hunter, джерело
@ jpmc26 так, у форматі ini Windows містяться обхідні шляхи постачальника для зворотної сумісності, охоплені NDA, тому є випадки, коли будь-яка відкрита реалізація не буде повністю сумісною з нею. Таким чином, у вас є файл, який виглядає майже так само, як файл .ini, але не буде вести себе так само. Було б краще використовувати те, що не призводить до цієї плутанини.
додано Автор Rob Hunter, джерело
Використання "схожих на ... файли INI у Microsoft Windows", здається, є поганою ідеєю, як на тій підставі, що він не є особливо гнучким форматом, а тому, що "подібний" передбачає недокументовані несумісності.
додано Автор Rob Hunter, джерело
@PeteKirkham Це скоріше проблема навпаки. Windows, як правило, має купу недокументованих лайно, що вибухає на вас. Python має тенденцію бути добре задокументованим і простим. Якщо ви все, що вам потрібно, є прості пари ключ/значення ( можливо з розділами), це досить хороший вибір. Я підозрюю, що це охоплює 90% випадків використання. Якщо файли налаштувань .NET були замість жахливого xml з схемою, яка насправді кодує маскування під час налаштування, ми всі були б краще.
додано Автор jmibanez, джерело
@PeteKirkham Не дуже. ІНІ найкраще підходить для простих випадків використання в першу чергу, швидше за все, ви можете уникнути будь-яких несумісностей. Вони також не мають значення, якщо ви не споживаєте файл з двома різними мовами, і навіть якщо ви є, ви, ймовірно, можете знайти відкриті реалізації на будь-якій мові (що дозволяє або не мати несумісності, або, як мінімум, точно знати, що вони є). Я згоден, що ви повинні використовувати інший формат, якщо ваш випадок використання є досить складним, щоб ви почали працювати в них, або якщо ви не можете знайти існуючу реалізацію, якій можна довіряти, але це не є звичайним явищем.
додано Автор jmibanez, джерело
@ PeteKirkham Ви пишете весь свій код, щоб бути сумісним з Windows, Linux і Mac, на всякий випадок, якщо він коли-небудь повинен бути перенесений? Ви використовуєте xml у випадку, якщо файл одного дня повинен бути довільно складним? Ми постійно приймаємо рішення про компроміси на основі того, що, на наш погляд, є імовірним, а що ні. Чесно кажучи, я вважаю, що найпростішим способом уникнути проблем, про які ви говорите, є просто уникнути впровадження INI в Windows. Якщо щось вже використовується, ви все одно застрягли з INI.
додано Автор jmibanez, джерело
@ PeteKirkham Я нічого не можу повірити типу користувачів, яких ви описуєте. Ті, які не можуть використовувати формат ConfigParser, можуть, на мою думку, також не заповнювати JSON і XML, вони потребують графічного інтерфейсу з максимальною кнопкою 1.
додано Автор CodeMonkey, джерело
@ PeteKirkham саме моя точка, або ви даєте їм доступ до конфігураційного файлу безпосередньо, що є "небезпечним" у будь-якому випадку, будь то JSON, xml або ConfigParser. Або ж ви надаєте їм більш безпечний інтерфейс з вашої програми, і ви можете навіть використовувати двійковий формат, щоб зберегти конфігурацію з меншою ймовірністю (випадкового) втручання. Тоді вам також не потрібно зберігати китайські рядки для китайських додатків, оскільки переклади знаходяться у вашому додатку не в конфігурації, 不好?
додано Автор CodeMonkey, джерело
@ PeteKirkham Ну, це просто, це документально і це частина стандартної бібліотеки Python. Це може бути ідеальним рішенням для потреб ОП, тому що він шукає щось, що підтримується безпосередньо Python, і простіше, ніж JSON. Поки він не уточнює, які його потреби, я думаю, що ця відповідь може бути корисною для нього.
додано Автор CodeMonkey, джерело
Я збирався запропонувати по суті це - побачити, які типи конфігураційних файлів Python libs підтримують і вибрати один з них. Крім того, Powershell має поняття розділів даних, які дозволяють обмежити мовні конструкції Powershell - захищаючи від шкідливого коду. Якщо у Python є бібліотека, яка підтримує обмежену підмножину Python для конфігурації, що принаймні пом'якшує одну з мінусів проти ідеї в ОП.
додано Автор Χpẘ, джерело

Я довго працював з деякими відоме програмне забезпечення , яке має свої конфігураційні файли, написані на TCL, тому ідея не нова. Це спрацювало досить добре, оскільки користувачі, які не знали мови, могли все ще писати/редагувати прості конфігураційні файли за допомогою одного оператора set name value , тоді як більш просунуті користувачі та розробники могли б витягувати з цим складні трюки.

Я не думаю, що "конфігураційні файли можуть бути важкими для налагодження" є дійсною проблемою. До тих пір, поки ваша програма не змусить користувачів писати сценарії, ваші користувачі можуть завжди використовувати прості завдання у своїх конфігураційних файлах, що навряд чи важче отримати порівняно з JSON або XML.

Переписування конфігурації є проблемою, хоча це не так погано, як здається. Оновлення довільного коду неможливе, але завантаження конфігурації з файлу, його зміна і збереження назад. В основному, якщо ви виконуєте скрипт у конфігураційному файлі, який не є доступним лише для читання, ви просто залишите еквівалентний список операторів set name name після його збереження. Хороший натяк на те, що це станеться - це коментар "не редагувати" на початку файлу.

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

Переконайтеся, що ви використовуєте відповідні пісочниці при виконанні ваших конфігураційних файлів.

1
додано
"Програмне забезпечення" є незліченним іменником, тому воно має бути " деяким відомим програмним забезпеченням."
додано Автор jmibanez, джерело
ІТ КПІ - Python
ІТ КПІ - Python
625 учасників

Канал обговорень про всякі штуки зі світу пайтону. Прохання: 0. мати повагу одне до одного; 1. не матюкатися в сторону людей; 2. не захламляти тред повідомленнями по одному слову;

ІТ КПІ - JavaScript
ІТ КПІ - JavaScript
504 учасників

співтовариство javascript розробників в Telegram