Как максимально просто хранить/загружать настройки вашего python-приложения ?

Если вы часто пишете что-то на python — необязательно даже какие-то большие проекты, просто какие админские утилиты под себя, — то рано или поздно придется задуматься о хранении настроек вашего приложения/скрипта.Конечно для совсем небольшого скрипта многие просто делают кортеж типа «опция»-«значение», сбрасывают его в простой текстовый файл и потом с ним как-то работают.Очевидно, что это подходит для скриптов, которые будут поддерживаться со временем.

Кроме того в силу своей гибкости python позволяет создать файл вроде settings.py и исполнять его на уровне кода.
То есть просто сделать settings.py таким :

import os.path as path
conf_path = path.join(path.dirname(__file__), "config")
my_settings = {
    'item 1' : "value 1",
    'item 2' : "value 2",
     ...
}

А потом его импортировать и как-то работать :

import settings
...
def main():
    ...
    print settings.conf_path
    ...

Но какждый раз лезть в settings.py и менять там какие-то опции это явно не комильфо.Следует ,как мне кажется, максмимально разделять логику и настройки.

Человечество уже давно придумало такую штуку, как XML. Существует огромное число библиотек для работы с XML и python-биндингов к ним. Несложно сериализовать обьекты в XML. Очень много софта используют XML для хранения настроек. Самый близкий пример — plist файлы в Mac OS/iOS и т.д.

Но мне кажется есть как минимум один недостаток (кроме производительности) — такой конфиг как неудобно редактировать руками человеку.Смотреть на портянку тегов как-то не очень.

Поэтому есть компромисс между XML и простыми текстовыми настройками — это так называемые .conf файлы, использумые широко в *nix/linux софте. Например, smb.conf для настроек сервера samba :

Синтаксис такого файла прост : он состоит из одного или более именованных разделов, каждый из которых может содержать отдельные параметры с именами и значениями.Разделом являются строки, начинающиеся с «[» и заканчивающиеся на  «]«. Значение в квадратных скобках —  название раздела, и может содержать любые символы, кроме квадратных скобок.

Простой пример :

[database_connection]
dbtype = mysql
url = http://localhost:3306
username = admin
password = admin_password

Сохраним на вымышленный конфиг подключения к серверу БД как dbconnect.conf.

Теперь каким образом без ручного считывания и парсинга этого файла сделать класс аля Settings? Да все просто. Уже написан отличный модуль ConfigParser, о котором собственно весь пост. Ставим этот модуль при помощи easy_install :

sudo easy_install ConfigParser

Или при помощи pip. В моей K/Ubuntu 11.10 для python 2.7 он уже установлен.И так, пилим класс (пусть будет в отдельном файле MyBDConfig.py):

from ConfigParser import SafeConfigParser

class BDProperties:
        def __init__(self, fname):
                self.filename = fname;
                self.cfgParser = SafeConfigParser();
        def load(self):
                self.cfgParser.read(self.filename);
        def getDBType(self):
                return self.cfgParser.get('database_connection','dbtype');
        def getURL(self):
                return self.cfgParser.get('database_connection','url');
        def getLogin(self):
                return self.cfgParser.get('database_connection','username');
        def getPass(self):
                return self.cfgParser.get('database_connection','password');

Итак, здесь мы импортировали необходимый нам модуль ConfigParser и использовали класс SafeConfigParser.Собственно после инициализации мы считываем наш конфиг-файл методом read(), который может принимать несколько путей к файлам и для каждого из них создать объект типа SafeConfigParser.
Для доступа к опции значению опции «op» секции «section» используем вызов метода get(«section»,»op»), как здесь :

...
        def getDBType(self):
                return self.cfgParser.get('database_connection','dbtype');
...

Проверяем — я для этого использую чумовую штуку под названием ipython :

Всё ок.Вот таким нехитрым способом можно считывать конфиги.read () возвращает список, содержащий имена файлов, успешно загруженных , чтобы ваше приложение могло определить, каких файлов конфигурации не хватает, и решить, следует ли игнорировать их.

Модуль легко подружить с юникодовыми конфигами, используя codecs.

С помощью этого модуля можно лекго пробежаться по структуре всего конфига, например так :

from ConfigParser import SafeConfigParser

parser = SafeConfigParser()
parser.read('/home/teddy/config/dbconnect.conf')

for section_name in parser.sections():
        print 'Section:', section_name
        print '  Options:', parser.options(section_name)
        for name, value in parser.items(section_name):
                print '  %s = %s' % (name, value)

Что даст :

teddy@teddy-System-Product-Name:~/config$ python explore.py
Section: database_connection
  Options: ['dbtype', 'url', 'username', 'password']
  dbtype = mysql
  url = http://localhost:3306
  username = admin
  password = admin_password
teddy@teddy-System-Product-Name:~/config$

В качестве разделителя опции и её значения можно использовать как «=«, так и «:«.
Остается лишь понять, как модифицировать наш конфиг. Для того чтобы модифицировать значение «value» опции «option» в секции «section» нужно сделать так :

...
ConfigParser.set('section','option','value');
...

Создать новый файл конфигурации что называется «from scratch» тоже легко :

import sys,ConfigParser

parser = ConfigParser.SafeConfigParser()

config_file = open("/home/teddy/config/new_config.conf","w")

parser.add_section('section 1')
parser.set('section 1', 'option 1', 'val 1')
parser.set('section 1', 'option 2', 'val 2')

for section in parser.sections():
    print section
    for name, value in parser.items(section):
        print '  %s = %r' % (name, value)

parser.write(config_file)

Как видим, был создан требуемый файл конфигурации :

Собственно, для того чтобы начать правильно хранить конфиги ваших приложений на python, этого достаточно.За бортом остались вопросы валидации, интерполяции значений и DEFAULT секции.Все это есть здесь :