2010-02-03 4 views
11

Я использую ConfigParser для загрузки данных из файла конфигурации следующим образом:Как исключить DEFAULT из Python ConfigParser .items()?

test.conf:

[myfiles] 
fileone: %(datadir)s/somefile.foo 
filetwo: %(datadir)s/nudderfile.foo 

load.py:

import ConfigParser 

config = ConfigParser.ConfigParser({'datadir': '/tmp'}) 
config.read('test.conf') 

print config.items('myfiles') 
print config.get('myfiles', 'datadir') 

Выход :

$ python load.py 
[('datadir', '/tmp'), ('filetwo', '/tmp/nudderfile.foo'), ('fileone', '/tmp/somefile.foo')] 
/tmp 

Я удивлен, что значения по умолчанию для переменной замены ('datadir', '/tmp') отображаются как часть. items() и .get() возвращаются, как если бы они были значениями в файле конфигурации. Ожидается ли такое поведение? Любая работа вокруг, так что я могу просто перебрать .items(), не получая значения словаря по умолчанию там, но все же используя магическую интерполяцию?

Ссылка: http://docs.python.org/library/configparser.html

Спасибо!

Обновление: Было указано, что это ожидаемое поведение: значения по умолчанию аналогичны любым другим парам имя/значение в файле конфигурации. Подобным же образом, пары имя/значение в конфигурационном файле, также доступны для «волшебной интерполяции», так что если я определяю:

foo: bar 
zap: %(foo)snowl 

я получить [... ('zap': 'barnowl')]

Это довольно аккуратный, но я до сих пор интересно, могу ли я выполнить то, что хочу выполнить: перебирать пары имя/значение в моих конфигурационных файлах с интерполяцией переменных без значений по умолчанию.

Мой конкретный сценарий таков: я хотел инициализировать объект конфигурации чем-то вроде {basedir: '/foo/bar'}, так как абсолютные пути к определенным файлам зависят от установки. Затем мне нужно передать этот объект конфигурации вокруг и выполнить различные итерации файлов по файлам. Я не хочу, чтобы каждый класс читал конфигурацию, чтобы знать, что она была инициализирована с определенными значениями по умолчанию и что она должна игнорировать их, поскольку они не являются фактическими файлами. Это возможно? Любой способ скрыть значения по умолчанию из .item() и .get(), но все еще иметь интерполяцию? Благодаря!

+2

Я не могу понять, почему это поведение по умолчанию, не говоря уже, почему нет никакого способа, чтобы выключить его. –

ответ

1

Попробуйте это:

config = ConfigParser.ConfigParser({'blahblahblah': 'blah'}) 
config.read('test.conf') 

blahblahblah ключ также появится в items, не потому, что шаблон в файле .ini, а потому, что вы указали его по умолчанию. Таким образом, ConfigParser обрабатывает значения по умолчанию: если он не может найти их в файле, он присваивает свои значения по умолчанию.

Так что, похоже, у вас есть простая путаница концепций здесь.

+0

Спасибо за разъяснение. Таким образом, словарь по умолчанию используется * both * для предоставления значений по умолчанию для определенных ключей и для «волшебной интерполяции» переменных, встроенных в файл конфигурации. Кроме того, переменные, определенные в файле конфигурации также используются для "волшебной интерполяции", так что если я определяю: Foo: бар зап:% (Foo) Snowl я получить [... ('Zap ':' barnowl ')] Это довольно аккуратно, но мне все же интересно, могу ли я выполнить то, что хочу: перебирать пары имя/значение в конфигурационных файлах с интерполяцией переменных без значений по умолчанию. – user264902

4

Как правило, я нашел класс configparser.Configparser очень полезным, но также не хватает. Others have, too.

Однако может быть подклассы и расширены, иногда хорошо, иногда не очень красиво (= очень зависит от реализации)

Вот решение вашей проблемы, испытанные в Python3:

class ConfigParser(configparser.ConfigParser): 
    """Can get options() without defaults 
    """ 
    def options(self, section, no_defaults=False, **kwargs): 
     if no_defaults: 
      try: 
       return list(self._sections[section].keys()) 
      except KeyError: 
       raise NoSectionError(section) 
     else: 
      return super().options(section, **kwargs) 

Это один из плохих примеров, потому что он частично копирует the source code из options(). Было бы лучше, если базовый класс configparser RawConfigParser предоставил бы внутренний геттер опций _options(self, section), который включал бы исключение, и options(), который использовал бы это. Затем в подклассе мы можем повторно использовать _options().

Для Python 2, я считаю, единственное изменение - super() звонок super(ConfigParser,self).

Вы можете использовать:

print config.options('myfiles', no_defaults=True) 

А также использовать этот список для перебора.

+0

Вы на правильном пути, однако он спросил о .items(), а не .options(). Я думаю, что это приведет его туда. –

+0

Я понял, что его вопрос заключается в том, как «перебирать пары имя/значение в моих конфигурационных файлах с помощью интерполяции переменных без параметров по умолчанию». И это то, что делает вышеупомянутый код. Для меня это точный ответ. К сожалению, как это часто бывает, плакат вопроса не кажется активным. В противном случае мы могли бы решить, подходит ли это для ответа или нет. – cfi

+0

Да, вопрос работает постоянно и требует внимания. Он использует .items в коде и в последнем предложении. Он спрашивает пары имя/вал, что и есть. Параметры просто возвращают ключи. Ваш ответ помог мне переопределить. Тем не менее, спасибо. –

2

Не можете ли вы просто отфильтровать значения по умолчанию?

.: например

filtered_items = [x for x in config.items('myfiles') if x[0] not in config.defaults()]