воскресенье, 7 июня 2015 г.

Конфиг для python скриптов

Захотелось тут на днях написать небольшую утилиту на python, дабы пользу себе нанести и язык заодно вспомнить. И оказалось, что требует она для своей работы конфиг. В мозгу сразу возникли слова: json, ini, xml, yaml и т.п. Но вот незадача - кто-то из них в стандартной библиотеке python отсутствует, где-то комментарии не поддерживаются, что-то имеет ужасный интерфейс работы из под python, опять же произвольную вложенность не везде можно использовать. И в добавок абсолютно все не поддерживают типизацию. Я уж было совсем приуныл, но в этот момент постучалась в мою голову одна светлая мысль: а python ведь скриптовый язык.

Действительно, что может быть проще - пишем конфиг на python, с его прекрасным синтаксисом, который решает все вышеперечисленные проблемы, а загрузить и распарсить его потом - проще, чем ini файл.
Вот допустим есть у нас вот такой конфиг:
param1 = ["a", "b"]
param2 = 3 + 5
Грузится он всего в 2 строчки:
config_data = {}
exec(open(config_path).read(), config_data)
print(config_data["param1"])
print(config_data["param2"])
Вуаля в словаре config_data, мы получаем все глобальные переменные из конфига, доступаться к ним можно по имени переменной. Типизация сохранена, произвольная вложенность, комменты, и главное использовать - проще некуда. Есть правда одна особенность, такой конфиг будет исполняемым, что делает его не совсем безопасным. Но если вы его пишете сами, а не качаете с сомнительных ресурсов - это даже скорее плюс, а не минус, гибкости добавляет такой, что никаким декларативным форматам и не снилось.
P.S.: Пример этот на 3-м питоне, для 2-го по моему синтаксис загрузки чуточку другой, но все так же делается в 2 строчки.
P.P.S.: Судя по комментариям не понятно, что: в config_path - можно передать полный путь к конфигу, без добавления его в sys.path. А для перечитывания конфига достаточно вызывать строчку с exec еще один раз, никаких reload делать не нужно.

7 комментариев:

  1. А чем обычный import этого модуля плох?

    ОтветитьУдалить
    Ответы
    1. - загрязняем область видимости нашего приложения
      - импорт файла, который лежит не рядом со скриптом, а в произвольной папке - не так просто сделать
      - перечитать такой файл без перезагрузки приложения тоже не совсем тривиально

      Удалить
    2. 1. решается через alias
      2. ну совсем произвольная редно используется, но согласен.
      3. reload (module) имеет грабли?

      Удалить
    3. По моему были какие-то особенности у reload, но не суть, тебе правда легче написать что-то вроде:
      import sys
      import importlib
      sys.path.insert(0, '/path/to/config')
      import config
      importlib.reload(config)

      вместо тех 2 строк? В любом случае смысл поста в том, что использовать python скрипт в качестве конфига, в большинстве случаев удобнее чем json, xml и т.п.

      Удалить
    4. ты как обычно усложняешь примеры из ответов и не усложняешь свои ;)
      В твоем примере нет ни другой директории, ни перечитывания конфига ;) Поэтому зря ты написал про свои "2 строчки"
      Но суть того, что конфиг для питона действительно интересно делать на питоне, это не меняет.

      Хотя это означает, что человек редактирующий твой "питон"-конфиг должен знать синтаксис питона. Не факт что он сложнее тех же xml или json, но последние более популярней и привычней.

      Удалить
    5. Вот уж не думал, что тебя так заденет. Но ты напраслину возводишь, в моем примере работает примерно вот так:
      def config():
      config_data = {}
      exec(open("/home/rean/projects/git/py-pacman-manager/config.py").read(), config_data)
      return config_data

      т.е. я могу указать полный путь к конфигу, без модификации sys.path, я могу вызвать функцию config второй раз и получу текущий конфиг, каждый вызов всегда заново его перечитывает.

      Удалить
    6. Добавил это в пост, возможно действительно не очевидно )

      Удалить