Как исключить 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 (), но все еще есть интерполяция? Спасибо!


person user264902    schedule 03.02.2010    source источник
comment
Я не могу понять, почему это поведение по умолчанию, не говоря уже о том, почему его нельзя отключить.   -  person Kyle Strand    schedule 22.12.2014


Ответы (4)


Как правило, я нашел очень полезным класс 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(). Было бы лучше, если бы базовый класс configparser RawConfigParser предоставил бы внутренний получатель параметров _options(self, section), который включал бы приведение исключения, и options(), который бы это использовал. Затем при создании подклассов мы могли бы повторно использовать _options().

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

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

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

А также используйте этот список для итерации.

person cfi    schedule 26.09.2012
comment
Вы на правильном пути, однако он спросил о .items (), а не о .options (). Я думаю, это его туда доставит. - person Gringo Suave; 11.01.2013
comment
Я понял, что его вопрос заключается в том, как перебирать пары имя / значение в моих файлах конфигурации с интерполяцией переменных без значений по умолчанию. И это то, что делает приведенный выше код. Для меня это точный ответ. К сожалению, как это часто бывает, автор вопроса не выглядит активным. В противном случае мы могли бы заставить его решить, приемлем ли это для ответа или нет. - person cfi; 11.01.2013
comment
Да, вопрос постоянно повторяется и требует внимания. Он использует .items в коде и в последнем предложении. Он запрашивает пары name / val, что и делает .items. Options просто возвращает ключи. Ваш ответ помог мне переопределить .items, поэтому спасибо. - person Gringo Suave; 12.01.2013
comment
В Python2 super вообще не работает, потому что ConfigParser - это класс старого стиля. (Да, действительно.) - person Kyle Strand; 22.12.2014
comment
Также обратите внимание, что self._sections[section].keys() (по крайней мере, в Python 2) включает запись с именем __name__ в каждом разделе, кроме DEFAULTSECT; эта запись не включена в реализацию options по умолчанию, поэтому ее, вероятно, следует здесь явно исключить. - person Kyle Strand; 23.12.2014

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

e.g.:

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

person mhristache    schedule 07.06.2016
comment
Нет, если у обоих одинаковое имя. - person Suuuehgi; 03.12.2019

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

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

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

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

person Eli Bendersky    schedule 03.02.2010
comment
Спасибо за разъяснения. Таким образом, словарь значений по умолчанию используется как для предоставления значений по умолчанию для определенных ключей и для магической интерполяции переменных, встроенных в файл конфигурации. Кроме того, переменные, определенные в файле конфигурации, также используются для магической интерполяции, поэтому, если я определю: foo: bar zap:% (foo) snowl, я получу [... ('zap': 'barnowl')] Это мило аккуратно, но мне все еще интересно, смогу ли я выполнить то, что хочу: перебирать пары имя / значение в моих файлах конфигурации с интерполяцией переменных без значений по умолчанию. - person user264902; 03.02.2010

Следующее должно предоставить вам только пары ключ / значение в разделе myfiles, не перечисляя их также в DEFAULT:

list(set(config.items('myfiles'))-set(config.items('DEFAULT')))
person Jeff    schedule 13.01.2019