Как исключить DEFAULT из Python ConfigParser.items()?
Я использую ConfigParser для загрузки данных из файла конфигурации следующим образом:
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(), но все еще иметь интерполяцию? Спасибо!
Ответы
Ответ 1
Вообще, я нашел класс configparser.Configparser очень полезным, но также отсутствующим. Другие тоже.
Тем не менее, он может быть разделен на подклассы и расширен, иногда красиво, иногда не так красиво (= очень зависит от реализации)
Вот решение вашей проблемы, протестированное в 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)
Это один из плохих примеров, потому что он частично копирует исходный код options()
. Было бы лучше, если бы базовый класс RawConfigParser
предоставил внутренний получатель параметров _options(self, section)
который включал бы приведение исключений, и options()
который использовал бы это. Затем в подклассах мы могли бы повторно использовать _options()
.
В Python 2 я считаю, что единственным изменением является вызов super()
для super(ConfigParser,self)
.
Затем вы можете использовать:
print config.options('myfiles', no_defaults=True)
А также использовать этот список для итерации.
Ответ 2
Не можете ли вы просто отфильтровать значения по умолчанию?
например:.
filtered_items = [x for x in config.items('myfiles') if x[0] not in config.defaults()]
Ответ 3
Попробуйте следующее:
config = ConfigParser.ConfigParser({'blahblahblah': 'blah'})
config.read('test.conf')
Клавиша blahblahblah
также появится в items
, а не потому, что это шаблон в файле .ini, а потому, что вы указали его как значение по умолчанию. Таким образом, ConfigParser обрабатывает значения по умолчанию: если он не может найти их в файле, он присваивает свои значения по умолчанию.
Итак, мне кажется, у вас есть простая путаница понятий здесь.
Ответ 4
Следующее должно дать вам только пары ключ/значение в разделе myfiles без перечисления их в DEFAULT:
list(set(config.items('myfiles'))-set(config.items('DEFAULT')))