如何从 Python ConfigParser .items() 中排除默认值?

Posted

技术标签:

【中文标题】如何从 Python ConfigParser .items() 中排除默认值?【英文标题】:How to exclude DEFAULTs from Python ConfigParser .items()? 【发布时间】:2011-01-12 10:56:17 【问题描述】:

我正在使用 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】:

以下内容应该只为您提供 myfiles 部分中的键/值对,而不列出 DEFAULT 中的那些:

list(set(config.items('myfiles'))-set(config.items('DEFAULT')))

【讨论】:

【参考方案2】:

你不能只过滤掉默认值吗?

例如:

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

【讨论】:

如果两者同名则不行。【参考方案3】:

一般来说,我发现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 将提供一个内部 getter 选项 _options(self, section) 将包含异常转换,并且 options() 将利用它,那就更好了。然后,在子类化中我们可以重用_options()

对于 Python 2,我相信唯一的变化是 super() 调用 super(ConfigParser,self)

然后您可以使用:

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

并且还使用该列表进行迭代。

【讨论】:

你在正确的轨道上,但是他问的是 .items(),而不是 .options()。我认为这会让他到达那里。 我理解他的问题是如何“迭代我的配置文件中的名称/值对,使用变量插值,没有默认值。”这就是上面的代码所做的。对我来说,这是一个准确的答案。不幸的是,通常情况下,问题的发布者似乎并不活跃。否则,我们可以让他决定这是否可以作为答案。 是的,这个问题一直存在,需要重点关注。他在代码和最后一句中使用了 .items。他要求 name/val 对,这就是 .items 所做的。选项只返回键。您的回答帮助我覆盖 .items 非常感谢。 在 Python2 中,super 根本不起作用,因为ConfigParser 是一个老式类。 (是的,真的。) 另外,请注意 self._sections[section].keys()(至少在 Python 2 中)在除 DEFAULTSECT 之外的每个部分中都包含一个名为 __name__ 的条目; options 的默认实现不包含此条目,因此可能应该在此处明确排除它。【参考方案4】:

试试这个:

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

blahblahblah 键也将出现在items 中,不是因为它是 .ini 文件中的模板,而是因为您将其指定为默认值。这就是 ConfigParser 处理默认值的方式:如果在文件中找不到它们,它会分配它们的默认值。

所以在我看来,您在这里有一个简单的概念混淆。

【讨论】:

感谢您的澄清。因此,默认字典 both 用于为某些键提供默认值,以及嵌入在配置文件中的变量的“魔术插值”。此外,配置文件中定义的变量也用于“魔术插值”,所以如果我定义: foo: bar zap: %(foo)snowl 我会得到 [... ('zap': 'barnowl')]这非常简洁,但我仍然想知道我是否可以完成我想要完成的事情:迭代我的配置文件中的名称/值对,使用变量插值,没有默认值。

以上是关于如何从 Python ConfigParser .items() 中排除默认值?的主要内容,如果未能解决你的问题,请参考以下文章

configparser 从 zip 加载配置文件

Python中配置文件解析模块-ConfigParser

python configparser 如何去除等号附近的空格

如何使用 configparser 更新值 python .ini 文件

Python:使用 ConfigParser vs json 文件 [关闭]

python封装configparser模块获取conf.ini值