如何从Python ConfigParser .items()中排除DEFAULTs?

19 投票
5 回答
10785 浏览
提问于 2025-04-15 18:49

我正在使用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() 中隐藏默认值,但仍然能进行变量替换呢?谢谢!

5 个回答

5

难道你不能把默认值过滤掉吗?

比如说:

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

6

我特意注册了一个账号来回答这个问题。因为在我搜索的时候,这个问题在谷歌上是最热门的。

我深入研究了ConfigParser的源代码,找到了我认为简单又有效的解决方案。

RawConfigParser类(ConfigParser继承自这个类)中,有一个叫default_section的关键字参数。我通过以下方式实例化,成功忽略了配置中的DEFAULT部分:

from configparser import ConfigParser

parser = ConfigParser(default_section=None)

希望这也能帮助到其他人。

11

一般来说,我发现 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)

还可以用这个列表来进行迭代。

撰写回答